summaryrefslogtreecommitdiffstats
path: root/dom/ipc/ContentChild.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/ipc/ContentChild.cpp')
-rw-r--r--dom/ipc/ContentChild.cpp3310
1 files changed, 3310 insertions, 0 deletions
diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp
new file mode 100644
index 000000000..ca4acf114
--- /dev/null
+++ b/dom/ipc/ContentChild.cpp
@@ -0,0 +1,3310 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifdef MOZ_WIDGET_GTK
+#include <gtk/gtk.h>
+#endif
+
+#include "ContentChild.h"
+
+#include "BlobChild.h"
+#include "CrashReporterChild.h"
+#include "GeckoProfiler.h"
+#include "TabChild.h"
+#include "HandlerServiceChild.h"
+
+#include "mozilla/Attributes.h"
+#include "mozilla/LookAndFeel.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/ProcessHangMonitorIPC.h"
+#include "mozilla/Unused.h"
+#include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h"
+#include "mozilla/docshell/OfflineCacheUpdateChild.h"
+#include "mozilla/dom/ContentBridgeChild.h"
+#include "mozilla/dom/ContentBridgeParent.h"
+#include "mozilla/dom/VideoDecoderManagerChild.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/DataTransfer.h"
+#include "mozilla/dom/DOMStorageIPC.h"
+#include "mozilla/dom/ExternalHelperAppChild.h"
+#include "mozilla/dom/FlyWebPublishedServerIPC.h"
+#include "mozilla/dom/GetFilesHelper.h"
+#include "mozilla/dom/PCrashReporterChild.h"
+#include "mozilla/dom/ProcessGlobal.h"
+#include "mozilla/dom/PushNotifier.h"
+#include "mozilla/dom/workers/ServiceWorkerManager.h"
+#include "mozilla/dom/nsIContentChild.h"
+#include "mozilla/gfx/gfxVars.h"
+#include "mozilla/psm/PSMContentListener.h"
+#include "mozilla/hal_sandbox/PHalChild.h"
+#include "mozilla/ipc/BackgroundChild.h"
+#include "mozilla/ipc/FileDescriptorSetChild.h"
+#include "mozilla/ipc/FileDescriptorUtils.h"
+#include "mozilla/ipc/GeckoChildProcessHost.h"
+#include "mozilla/ipc/ProcessChild.h"
+#include "mozilla/ipc/PSendStreamChild.h"
+#include "mozilla/ipc/TestShellChild.h"
+#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
+#include "mozilla/layers/APZChild.h"
+#include "mozilla/layers/CompositorBridgeChild.h"
+#include "mozilla/layers/ContentProcessController.h"
+#include "mozilla/layers/ImageBridgeChild.h"
+#include "mozilla/layout/RenderFrameChild.h"
+#include "mozilla/net/NeckoChild.h"
+#include "mozilla/net/CaptivePortalService.h"
+#include "mozilla/plugins/PluginInstanceParent.h"
+#include "mozilla/plugins/PluginModuleParent.h"
+#include "mozilla/widget/WidgetMessageUtils.h"
+#include "nsBaseDragService.h"
+#include "mozilla/media/MediaChild.h"
+#include "mozilla/BasePrincipal.h"
+#include "mozilla/WebBrowserPersistDocumentChild.h"
+#include "imgLoader.h"
+#include "GMPServiceChild.h"
+
+#if defined(MOZ_CONTENT_SANDBOX)
+#if defined(XP_WIN)
+#define TARGET_SANDBOX_EXPORTS
+#include "mozilla/sandboxTarget.h"
+#elif defined(XP_LINUX)
+#include "mozilla/Sandbox.h"
+#include "mozilla/SandboxInfo.h"
+
+// Remove this include with Bug 1104619
+#include "CubebUtils.h"
+#elif defined(XP_MACOSX)
+#include "mozilla/Sandbox.h"
+#endif
+#endif
+
+#include "mozilla/Unused.h"
+
+#include "mozInlineSpellChecker.h"
+#include "nsDocShell.h"
+#include "nsIConsoleListener.h"
+#include "nsICycleCollectorListener.h"
+#include "nsIIdlePeriod.h"
+#include "nsIDragService.h"
+#include "nsIIPCBackgroundChildCreateCallback.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsIMemoryReporter.h"
+#include "nsIMemoryInfoDumper.h"
+#include "nsIMutable.h"
+#include "nsIObserverService.h"
+#include "nsIScriptSecurityManager.h"
+#include "nsScreenManagerProxy.h"
+#include "nsMemoryInfoDumper.h"
+#include "nsServiceManagerUtils.h"
+#include "nsStyleSheetService.h"
+#include "nsVariant.h"
+#include "nsXULAppAPI.h"
+#include "nsIScriptError.h"
+#include "nsIConsoleService.h"
+#include "nsJSEnvironment.h"
+#include "SandboxHal.h"
+#include "nsDebugImpl.h"
+#include "nsHashPropertyBag.h"
+#include "nsLayoutStylesheetCache.h"
+#include "nsThreadManager.h"
+#include "nsAnonymousTemporaryFile.h"
+#include "nsISpellChecker.h"
+#include "nsClipboardProxy.h"
+#include "nsDirectoryService.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsContentPermissionHelper.h"
+#ifdef NS_PRINTING
+#include "nsPrintingProxy.h"
+#endif
+
+#include "IHistory.h"
+#include "nsNetUtil.h"
+
+#include "base/message_loop.h"
+#include "base/process_util.h"
+#include "base/task.h"
+
+#include "nsChromeRegistryContent.h"
+#include "nsFrameMessageManager.h"
+
+#include "nsIGeolocationProvider.h"
+#include "mozilla/dom/PMemoryReportRequestChild.h"
+#include "mozilla/dom/PCycleCollectWithLogsChild.h"
+
+#include "nsIScriptSecurityManager.h"
+#include "nsHostObjectProtocolHandler.h"
+
+#ifdef MOZ_WEBRTC
+#include "signaling/src/peerconnection/WebrtcGlobalChild.h"
+#endif
+
+#ifdef MOZ_PERMISSIONS
+#include "nsPermission.h"
+#include "nsPermissionManager.h"
+#endif
+
+#include "PermissionMessageUtils.h"
+
+#if defined(MOZ_WIDGET_ANDROID)
+#include "APKOpen.h"
+#endif
+
+#if defined(MOZ_WIDGET_GONK)
+#include "nsVolume.h"
+#include "nsVolumeService.h"
+#include "SpeakerManagerService.h"
+#endif
+
+#ifdef XP_WIN
+#include <process.h>
+#define getpid _getpid
+#include "mozilla/widget/AudioSession.h"
+#endif
+
+#ifdef MOZ_X11
+#include "mozilla/X11Util.h"
+#endif
+
+#ifdef ACCESSIBILITY
+#include "nsAccessibilityService.h"
+#endif
+
+#include "mozilla/dom/File.h"
+#include "mozilla/dom/PPresentationChild.h"
+#include "mozilla/dom/PresentationIPCService.h"
+#include "mozilla/ipc/InputStreamUtils.h"
+
+#ifdef MOZ_WEBSPEECH
+#include "mozilla/dom/PSpeechSynthesisChild.h"
+#endif
+
+#include "ProcessUtils.h"
+#include "URIUtils.h"
+#include "nsContentUtils.h"
+#include "nsIPrincipal.h"
+#include "DomainPolicy.h"
+#include "mozilla/dom/ipc/StructuredCloneData.h"
+#include "mozilla/dom/time/DateCacheCleaner.h"
+#include "mozilla/net/NeckoMessageUtils.h"
+#include "mozilla/widget/PuppetBidiKeyboard.h"
+#include "mozilla/RemoteSpellCheckEngineChild.h"
+#include "GMPServiceChild.h"
+#include "gfxPlatform.h"
+#include "nscore.h" // for NS_FREE_PERMANENT_DATA
+#include "VRManagerChild.h"
+
+using namespace mozilla;
+using namespace mozilla::docshell;
+using namespace mozilla::dom::ipc;
+using namespace mozilla::dom::workers;
+using namespace mozilla::media;
+using namespace mozilla::embedding;
+using namespace mozilla::gmp;
+using namespace mozilla::hal_sandbox;
+using namespace mozilla::ipc;
+using namespace mozilla::layers;
+using namespace mozilla::layout;
+using namespace mozilla::net;
+using namespace mozilla::jsipc;
+using namespace mozilla::psm;
+using namespace mozilla::widget;
+#if defined(MOZ_WIDGET_GONK)
+using namespace mozilla::system;
+#endif
+using namespace mozilla::widget;
+
+namespace mozilla {
+namespace dom {
+
+class MemoryReportRequestChild : public PMemoryReportRequestChild,
+ public nsIRunnable
+{
+public:
+ NS_DECL_ISUPPORTS
+
+ MemoryReportRequestChild(bool aAnonymize,
+ const MaybeFileDesc& aDMDFile);
+ NS_IMETHOD Run() override;
+
+private:
+ virtual ~MemoryReportRequestChild();
+
+ bool mAnonymize;
+ FileDescriptor mDMDFile;
+};
+
+NS_IMPL_ISUPPORTS(MemoryReportRequestChild, nsIRunnable)
+
+MemoryReportRequestChild::MemoryReportRequestChild(
+ bool aAnonymize, const MaybeFileDesc& aDMDFile)
+: mAnonymize(aAnonymize)
+{
+ MOZ_COUNT_CTOR(MemoryReportRequestChild);
+ if (aDMDFile.type() == MaybeFileDesc::TFileDescriptor) {
+ mDMDFile = aDMDFile.get_FileDescriptor();
+ }
+}
+
+MemoryReportRequestChild::~MemoryReportRequestChild()
+{
+ MOZ_COUNT_DTOR(MemoryReportRequestChild);
+}
+
+// IPC sender for remote GC/CC logging.
+class CycleCollectWithLogsChild final
+ : public PCycleCollectWithLogsChild
+ , public nsICycleCollectorLogSink
+{
+public:
+ NS_DECL_ISUPPORTS
+
+ CycleCollectWithLogsChild(const FileDescriptor& aGCLog,
+ const FileDescriptor& aCCLog)
+ {
+ mGCLog = FileDescriptorToFILE(aGCLog, "w");
+ mCCLog = FileDescriptorToFILE(aCCLog, "w");
+ }
+
+ NS_IMETHOD Open(FILE** aGCLog, FILE** aCCLog) override
+ {
+ if (NS_WARN_IF(!mGCLog) || NS_WARN_IF(!mCCLog)) {
+ return NS_ERROR_FAILURE;
+ }
+ *aGCLog = mGCLog;
+ *aCCLog = mCCLog;
+ return NS_OK;
+ }
+
+ NS_IMETHOD CloseGCLog() override
+ {
+ MOZ_ASSERT(mGCLog);
+ fclose(mGCLog);
+ mGCLog = nullptr;
+ SendCloseGCLog();
+ return NS_OK;
+ }
+
+ NS_IMETHOD CloseCCLog() override
+ {
+ MOZ_ASSERT(mCCLog);
+ fclose(mCCLog);
+ mCCLog = nullptr;
+ SendCloseCCLog();
+ return NS_OK;
+ }
+
+ NS_IMETHOD GetFilenameIdentifier(nsAString& aIdentifier) override
+ {
+ return UnimplementedProperty();
+ }
+
+ NS_IMETHOD SetFilenameIdentifier(const nsAString& aIdentifier) override
+ {
+ return UnimplementedProperty();
+ }
+
+ NS_IMETHOD GetProcessIdentifier(int32_t *aIdentifier) override
+ {
+ return UnimplementedProperty();
+ }
+
+ NS_IMETHOD SetProcessIdentifier(int32_t aIdentifier) override
+ {
+ return UnimplementedProperty();
+ }
+
+ NS_IMETHOD GetGcLog(nsIFile** aPath) override
+ {
+ return UnimplementedProperty();
+ }
+
+ NS_IMETHOD GetCcLog(nsIFile** aPath) override
+ {
+ return UnimplementedProperty();
+ }
+
+private:
+ ~CycleCollectWithLogsChild()
+ {
+ if (mGCLog) {
+ fclose(mGCLog);
+ mGCLog = nullptr;
+ }
+ if (mCCLog) {
+ fclose(mCCLog);
+ mCCLog = nullptr;
+ }
+ // The XPCOM refcount drives the IPC lifecycle; see also
+ // DeallocPCycleCollectWithLogsChild.
+ Unused << Send__delete__(this);
+ }
+
+ nsresult UnimplementedProperty()
+ {
+ MOZ_ASSERT(false, "This object is a remote GC/CC logger;"
+ " this property isn't meaningful.");
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ FILE* mGCLog;
+ FILE* mCCLog;
+};
+
+NS_IMPL_ISUPPORTS(CycleCollectWithLogsChild, nsICycleCollectorLogSink);
+
+class AlertObserver
+{
+public:
+
+ AlertObserver(nsIObserver *aObserver, const nsString& aData)
+ : mObserver(aObserver)
+ , mData(aData)
+ {
+ }
+
+ ~AlertObserver() {}
+
+ bool ShouldRemoveFrom(nsIObserver* aObserver,
+ const nsString& aData) const
+ {
+ return (mObserver == aObserver && mData == aData);
+ }
+
+ bool Observes(const nsString& aData) const
+ {
+ return mData.Equals(aData);
+ }
+
+ bool Notify(const nsCString& aType) const
+ {
+ mObserver->Observe(nullptr, aType.get(), mData.get());
+ return true;
+ }
+
+private:
+ nsCOMPtr<nsIObserver> mObserver;
+ nsString mData;
+};
+
+class ConsoleListener final : public nsIConsoleListener
+{
+public:
+ explicit ConsoleListener(ContentChild* aChild)
+ : mChild(aChild) {}
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSICONSOLELISTENER
+
+private:
+ ~ConsoleListener() {}
+
+ ContentChild* mChild;
+ friend class ContentChild;
+};
+
+NS_IMPL_ISUPPORTS(ConsoleListener, nsIConsoleListener)
+
+// Before we send the error to the parent process (which
+// involves copying the memory), truncate any long lines. CSS
+// errors in particular share the memory for long lines with
+// repeated errors, but the IPC communication we're about to do
+// will break that sharing, so we better truncate now.
+static void
+TruncateString(nsAString& aString)
+{
+ if (aString.Length() > 1000) {
+ aString.Truncate(1000);
+ }
+}
+
+NS_IMETHODIMP
+ConsoleListener::Observe(nsIConsoleMessage* aMessage)
+{
+ if (!mChild) {
+ return NS_OK;
+ }
+
+ nsCOMPtr<nsIScriptError> scriptError = do_QueryInterface(aMessage);
+ if (scriptError) {
+ nsAutoString msg, sourceName, sourceLine;
+ nsXPIDLCString category;
+ uint32_t lineNum, colNum, flags;
+
+ nsresult rv = scriptError->GetErrorMessage(msg);
+ NS_ENSURE_SUCCESS(rv, rv);
+ TruncateString(msg);
+ rv = scriptError->GetSourceName(sourceName);
+ NS_ENSURE_SUCCESS(rv, rv);
+ TruncateString(sourceName);
+ rv = scriptError->GetSourceLine(sourceLine);
+ NS_ENSURE_SUCCESS(rv, rv);
+ TruncateString(sourceLine);
+
+ rv = scriptError->GetCategory(getter_Copies(category));
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = scriptError->GetLineNumber(&lineNum);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = scriptError->GetColumnNumber(&colNum);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = scriptError->GetFlags(&flags);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mChild->SendScriptError(msg, sourceName, sourceLine,
+ lineNum, colNum, flags, category);
+ return NS_OK;
+ }
+
+ nsXPIDLString msg;
+ nsresult rv = aMessage->GetMessageMoz(getter_Copies(msg));
+ NS_ENSURE_SUCCESS(rv, rv);
+ mChild->SendConsoleMessage(msg);
+ return NS_OK;
+}
+
+class BackgroundChildPrimer final :
+ public nsIIPCBackgroundChildCreateCallback
+{
+public:
+ BackgroundChildPrimer()
+ { }
+
+ NS_DECL_ISUPPORTS
+
+private:
+ ~BackgroundChildPrimer()
+ { }
+
+ virtual void
+ ActorCreated(PBackgroundChild* aActor) override
+ {
+ MOZ_ASSERT(aActor, "Failed to create a PBackgroundChild actor!");
+ }
+
+ virtual void
+ ActorFailed() override
+ {
+ MOZ_CRASH("Failed to create a PBackgroundChild actor!");
+ }
+};
+
+NS_IMPL_ISUPPORTS(BackgroundChildPrimer, nsIIPCBackgroundChildCreateCallback)
+
+ContentChild* ContentChild::sSingleton;
+
+ContentChild::ContentChild()
+ : mID(uint64_t(-1))
+#if defined(XP_WIN) && defined(ACCESSIBILITY)
+ , mMsaaID(0)
+#endif
+ , mCanOverrideProcessName(true)
+ , mIsAlive(true)
+ , mShuttingDown(false)
+{
+ // This process is a content process, so it's clearly running in
+ // multiprocess mode!
+ nsDebugImpl::SetMultiprocessMode("Child");
+}
+
+ContentChild::~ContentChild()
+{
+#ifndef NS_FREE_PERMANENT_DATA
+ NS_RUNTIMEABORT("Content Child shouldn't be destroyed.");
+#endif
+}
+
+NS_INTERFACE_MAP_BEGIN(ContentChild)
+ NS_INTERFACE_MAP_ENTRY(nsIContentChild)
+ NS_INTERFACE_MAP_ENTRY(nsIWindowProvider)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentChild)
+NS_INTERFACE_MAP_END
+
+bool
+ContentChild::Init(MessageLoop* aIOLoop,
+ base::ProcessId aParentPid,
+ IPC::Channel* aChannel)
+{
+#ifdef MOZ_WIDGET_GTK
+ // We need to pass a display down to gtk_init because it's not going to
+ // use the one from the environment on its own when deciding which backend
+ // to use, and when starting under XWayland, it may choose to start with
+ // the wayland backend instead of the x11 backend.
+ // The DISPLAY environment variable is normally set by the parent process.
+ char* display_name = PR_GetEnv("DISPLAY");
+ if (display_name) {
+ int argc = 3;
+ char option_name[] = "--display";
+ char* argv[] = {
+ // argv0 is unused because g_set_prgname() was called in
+ // XRE_InitChildProcess().
+ nullptr,
+ option_name,
+ display_name,
+ nullptr
+ };
+ char** argvp = argv;
+ gtk_init(&argc, &argvp);
+ } else {
+ gtk_init(nullptr, nullptr);
+ }
+#endif
+
+#ifdef MOZ_X11
+ // Do this after initializing GDK, or GDK will install its own handler.
+ XRE_InstallX11ErrorHandler();
+#endif
+
+ NS_ASSERTION(!sSingleton, "only one ContentChild per child");
+
+ // Once we start sending IPC messages, we need the thread manager to be
+ // initialized so we can deal with the responses. Do that here before we
+ // try to construct the crash reporter.
+ nsresult rv = nsThreadManager::get().Init();
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return false;
+ }
+
+ if (!Open(aChannel, aParentPid, aIOLoop)) {
+ return false;
+ }
+ sSingleton = this;
+
+ // If communications with the parent have broken down, take the process
+ // down so it's not hanging around.
+ GetIPCChannel()->SetAbortOnError(true);
+#if defined(XP_WIN) && defined(ACCESSIBILITY)
+ GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_A11Y_REENTRY);
+#endif
+
+#ifdef MOZ_X11
+ // Send the parent our X socket to act as a proxy reference for our X
+ // resources.
+ int xSocketFd = ConnectionNumber(DefaultXDisplay());
+ SendBackUpXResources(FileDescriptor(xSocketFd));
+#endif
+
+#ifdef MOZ_CRASHREPORTER
+ SendPCrashReporterConstructor(CrashReporter::CurrentThreadId(),
+ XRE_GetProcessType());
+#endif
+
+ SendGetProcessAttributes(&mID, &mIsForApp, &mIsForBrowser);
+ InitProcessAttributes();
+
+#ifdef NS_PRINTING
+ // Force the creation of the nsPrintingProxy so that it's IPC counterpart,
+ // PrintingParent, is always available for printing initiated from the parent.
+ RefPtr<nsPrintingProxy> printingProxy = nsPrintingProxy::GetInstance();
+#endif
+
+ return true;
+}
+
+void
+ContentChild::InitProcessAttributes()
+{
+#ifdef MOZ_WIDGET_GONK
+ if (mIsForApp && !mIsForBrowser) {
+ SetProcessName(NS_LITERAL_STRING("(Preallocated app)"), false);
+ } else {
+ SetProcessName(NS_LITERAL_STRING("Browser"), false);
+ }
+#else
+ SetProcessName(NS_LITERAL_STRING("Web Content"), true);
+#endif
+}
+
+void
+ContentChild::SetProcessName(const nsAString& aName, bool aDontOverride)
+{
+ if (!mCanOverrideProcessName) {
+ return;
+ }
+
+ char* name;
+ if ((name = PR_GetEnv("MOZ_DEBUG_APP_PROCESS")) &&
+ aName.EqualsASCII(name)) {
+#ifdef OS_POSIX
+ printf_stderr("\n\nCHILDCHILDCHILDCHILD\n [%s] debug me @%d\n\n", name,
+ getpid());
+ sleep(30);
+#elif defined(OS_WIN)
+ // Windows has a decent JIT debugging story, so NS_DebugBreak does the
+ // right thing.
+ NS_DebugBreak(NS_DEBUG_BREAK,
+ "Invoking NS_DebugBreak() to debug child process",
+ nullptr, __FILE__, __LINE__);
+#endif
+ }
+
+ mProcessName = aName;
+ mozilla::ipc::SetThisProcessName(NS_LossyConvertUTF16toASCII(aName).get());
+
+ if (aDontOverride) {
+ mCanOverrideProcessName = false;
+ }
+}
+
+NS_IMETHODIMP
+ContentChild::ProvideWindow(mozIDOMWindowProxy* aParent,
+ uint32_t aChromeFlags,
+ bool aCalledFromJS,
+ bool aPositionSpecified,
+ bool aSizeSpecified,
+ nsIURI* aURI,
+ const nsAString& aName,
+ const nsACString& aFeatures,
+ bool aForceNoOpener,
+ bool* aWindowIsNew,
+ mozIDOMWindowProxy** aReturn)
+{
+ return ProvideWindowCommon(nullptr, aParent, false, aChromeFlags,
+ aCalledFromJS, aPositionSpecified,
+ aSizeSpecified, aURI, aName, aFeatures,
+ aForceNoOpener, aWindowIsNew, aReturn);
+}
+
+nsresult
+ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
+ mozIDOMWindowProxy* aParent,
+ bool aIframeMoz,
+ uint32_t aChromeFlags,
+ bool aCalledFromJS,
+ bool aPositionSpecified,
+ bool aSizeSpecified,
+ nsIURI* aURI,
+ const nsAString& aName,
+ const nsACString& aFeatures,
+ bool aForceNoOpener,
+ bool* aWindowIsNew,
+ mozIDOMWindowProxy** aReturn)
+{
+ *aReturn = nullptr;
+
+ nsAutoPtr<IPCTabContext> ipcContext;
+ TabId openerTabId = TabId(0);
+
+ if (aTabOpener) {
+ PopupIPCTabContext context;
+ openerTabId = aTabOpener->GetTabId();
+ context.opener() = openerTabId;
+ context.isMozBrowserElement() = aTabOpener->IsMozBrowserElement();
+ ipcContext = new IPCTabContext(context);
+ } else {
+ // It's possible to not have a TabChild opener in the case
+ // of ServiceWorker::OpenWindow.
+ UnsafeIPCTabContext unsafeTabContext;
+ ipcContext = new IPCTabContext(unsafeTabContext);
+ }
+
+ MOZ_ASSERT(ipcContext);
+ TabId tabId;
+ SendAllocateTabId(openerTabId,
+ *ipcContext,
+ GetID(),
+ &tabId);
+
+ TabContext newTabContext = aTabOpener ? *aTabOpener : TabContext();
+ RefPtr<TabChild> newChild = new TabChild(this, tabId,
+ newTabContext, aChromeFlags);
+ if (NS_FAILED(newChild->Init())) {
+ return NS_ERROR_ABORT;
+ }
+
+ if (aTabOpener) {
+ MOZ_ASSERT(ipcContext->type() == IPCTabContext::TPopupIPCTabContext);
+ ipcContext->get_PopupIPCTabContext().opener() = aTabOpener;
+ }
+
+ Unused << SendPBrowserConstructor(
+ // We release this ref in DeallocPBrowserChild
+ RefPtr<TabChild>(newChild).forget().take(),
+ tabId, *ipcContext, aChromeFlags,
+ GetID(), IsForApp(), IsForBrowser());
+
+ nsString name(aName);
+ nsAutoCString features(aFeatures);
+ nsTArray<FrameScriptInfo> frameScripts;
+ nsCString urlToLoad;
+
+ PRenderFrameChild* renderFrame = newChild->SendPRenderFrameConstructor();
+ TextureFactoryIdentifier textureFactoryIdentifier;
+ uint64_t layersId = 0;
+
+ if (aIframeMoz) {
+ MOZ_ASSERT(aTabOpener);
+ nsAutoCString url;
+ if (aURI) {
+ aURI->GetSpec(url);
+ } else {
+ // We can't actually send a nullptr up as the URI, since IPDL doesn't let us
+ // send nullptr's for primitives. We indicate that the nsString for the URI
+ // should be converted to a nullptr by voiding the string.
+ url.SetIsVoid(true);
+ }
+
+ newChild->SendBrowserFrameOpenWindow(aTabOpener, renderFrame, NS_ConvertUTF8toUTF16(url),
+ name, NS_ConvertUTF8toUTF16(features),
+ aWindowIsNew, &textureFactoryIdentifier,
+ &layersId);
+ } else {
+ nsAutoCString baseURIString;
+ if (aTabOpener) {
+ auto* opener = nsPIDOMWindowOuter::From(aParent);
+ nsCOMPtr<nsIDocument> doc = opener->GetDoc();
+ nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
+ if (!baseURI) {
+ NS_ERROR("nsIDocument didn't return a base URI");
+ return NS_ERROR_FAILURE;
+ }
+
+ baseURI->GetSpec(baseURIString);
+ }
+
+ auto* opener = nsPIDOMWindowOuter::From(aParent);
+ nsIDocShell* openerShell;
+ RefPtr<nsDocShell> openerDocShell;
+ float fullZoom = 1.0f;
+ if (opener && (openerShell = opener->GetDocShell())) {
+ openerDocShell = static_cast<nsDocShell*>(openerShell);
+ nsCOMPtr<nsIContentViewer> cv;
+ openerDocShell->GetContentViewer(getter_AddRefs(cv));
+ if (cv) {
+ cv->GetFullZoom(&fullZoom);
+ }
+ }
+
+ nsresult rv;
+ if (!SendCreateWindow(aTabOpener, newChild, renderFrame,
+ aChromeFlags, aCalledFromJS, aPositionSpecified,
+ aSizeSpecified,
+ features,
+ baseURIString,
+ openerDocShell
+ ? openerDocShell->GetOriginAttributes()
+ : DocShellOriginAttributes(),
+ fullZoom,
+ &rv,
+ aWindowIsNew,
+ &frameScripts,
+ &urlToLoad,
+ &textureFactoryIdentifier,
+ &layersId)) {
+ PRenderFrameChild::Send__delete__(renderFrame);
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ if (NS_FAILED(rv)) {
+ PRenderFrameChild::Send__delete__(renderFrame);
+ return rv;
+ }
+ }
+ if (!*aWindowIsNew) {
+ PRenderFrameChild::Send__delete__(renderFrame);
+ return NS_ERROR_ABORT;
+ }
+
+ if (layersId == 0) { // if renderFrame is invalid.
+ PRenderFrameChild::Send__delete__(renderFrame);
+ renderFrame = nullptr;
+ }
+
+ ShowInfo showInfo(EmptyString(), false, false, true, false, 0, 0, 0);
+ auto* opener = nsPIDOMWindowOuter::From(aParent);
+ nsIDocShell* openerShell;
+ if (opener && (openerShell = opener->GetDocShell())) {
+ nsCOMPtr<nsILoadContext> context = do_QueryInterface(openerShell);
+ showInfo = ShowInfo(EmptyString(), false,
+ context->UsePrivateBrowsing(), true, false,
+ aTabOpener->mDPI, aTabOpener->mRounding,
+ aTabOpener->mDefaultScale);
+ }
+
+ // Set the opener window for this window before we start loading the document
+ // inside of it. We have to do this before loading the remote scripts, because
+ // they can poke at the document and cause the nsDocument to be created before
+ // the openerwindow
+ nsCOMPtr<mozIDOMWindowProxy> windowProxy = do_GetInterface(newChild->WebNavigation());
+ if (!aForceNoOpener && windowProxy && aParent) {
+ nsPIDOMWindowOuter* outer = nsPIDOMWindowOuter::From(windowProxy);
+ nsPIDOMWindowOuter* parent = nsPIDOMWindowOuter::From(aParent);
+ outer->SetOpenerWindow(parent, *aWindowIsNew);
+ }
+
+ // Unfortunately we don't get a window unless we've shown the frame. That's
+ // pretty bogus; see bug 763602.
+ newChild->DoFakeShow(textureFactoryIdentifier, layersId, renderFrame,
+ showInfo);
+
+ for (size_t i = 0; i < frameScripts.Length(); i++) {
+ FrameScriptInfo& info = frameScripts[i];
+ if (!newChild->RecvLoadRemoteScript(info.url(), info.runInGlobalScope())) {
+ MOZ_CRASH();
+ }
+ }
+
+ if (!urlToLoad.IsEmpty()) {
+ newChild->RecvLoadURL(urlToLoad, showInfo);
+ }
+
+ nsCOMPtr<mozIDOMWindowProxy> win = do_GetInterface(newChild->WebNavigation());
+ win.forget(aReturn);
+ return NS_OK;
+}
+
+void
+ContentChild::GetProcessName(nsAString& aName) const
+{
+ aName.Assign(mProcessName);
+}
+
+bool
+ContentChild::IsAlive() const
+{
+ return mIsAlive;
+}
+
+bool
+ContentChild::IsShuttingDown() const
+{
+ return mShuttingDown;
+}
+
+void
+ContentChild::GetProcessName(nsACString& aName) const
+{
+ aName.Assign(NS_ConvertUTF16toUTF8(mProcessName));
+}
+
+/* static */ void
+ContentChild::AppendProcessId(nsACString& aName)
+{
+ if (!aName.IsEmpty()) {
+ aName.Append(' ');
+ }
+ unsigned pid = getpid();
+ aName.Append(nsPrintfCString("(pid %u)", pid));
+}
+
+void
+ContentChild::InitGraphicsDeviceData()
+{
+ // Initialize the graphics platform. This may contact the parent process
+ // to read device preferences.
+ gfxPlatform::GetPlatform();
+}
+
+void
+ContentChild::InitXPCOM()
+{
+ // Do this as early as possible to get the parent process to initialize the
+ // background thread since we'll likely need database information very soon.
+ BackgroundChild::Startup();
+
+ nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
+ new BackgroundChildPrimer();
+ if (!BackgroundChild::GetOrCreateForCurrentThread(callback)) {
+ MOZ_CRASH("Failed to create PBackgroundChild!");
+ }
+
+ BlobChild::Startup(BlobChild::FriendKey());
+
+ nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
+ if (!svc) {
+ NS_WARNING("Couldn't acquire console service");
+ return;
+ }
+
+ mConsoleListener = new ConsoleListener(this);
+ if (NS_FAILED(svc->RegisterListener(mConsoleListener)))
+ NS_WARNING("Couldn't register console listener for child process");
+
+ bool isOffline, isLangRTL, haveBidiKeyboards;
+ bool isConnected;
+ ClipboardCapabilities clipboardCaps;
+ DomainPolicyClone domainPolicy;
+ StructuredCloneData initialData;
+ OptionalURIParams userContentSheetURL;
+
+ int32_t captivePortalState;
+ SendGetXPCOMProcessAttributes(&isOffline, &isConnected, &captivePortalState,
+ &isLangRTL, &haveBidiKeyboards,
+ &mAvailableDictionaries,
+ &clipboardCaps, &domainPolicy, &initialData,
+ &userContentSheetURL);
+ RecvSetOffline(isOffline);
+ RecvSetConnectivity(isConnected);
+ RecvSetCaptivePortalState(captivePortalState);
+ RecvBidiKeyboardNotify(isLangRTL, haveBidiKeyboards);
+
+ // Create the CPOW manager as soon as possible.
+ SendPJavaScriptConstructor();
+
+ if (domainPolicy.active()) {
+ nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
+ MOZ_ASSERT(ssm);
+ ssm->ActivateDomainPolicyInternal(getter_AddRefs(mPolicy));
+ if (!mPolicy) {
+ MOZ_CRASH("Failed to activate domain policy.");
+ }
+ mPolicy->ApplyClone(&domainPolicy);
+ }
+
+ nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1"));
+ if (nsCOMPtr<nsIClipboardProxy> clipboardProxy = do_QueryInterface(clipboard)) {
+ clipboardProxy->SetCapabilities(clipboardCaps);
+ }
+
+ {
+ AutoJSAPI jsapi;
+ if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) {
+ MOZ_CRASH();
+ }
+ ErrorResult rv;
+ JS::RootedValue data(jsapi.cx());
+ initialData.Read(jsapi.cx(), &data, rv);
+ if (NS_WARN_IF(rv.Failed())) {
+ MOZ_CRASH();
+ }
+ ProcessGlobal* global = ProcessGlobal::Get();
+ global->SetInitialProcessData(data);
+ }
+
+ // The stylesheet cache is not ready yet. Store this URL for future use.
+ nsCOMPtr<nsIURI> ucsURL = DeserializeURI(userContentSheetURL);
+ nsLayoutStylesheetCache::SetUserContentCSSURL(ucsURL);
+
+ // This will register cross-process observer.
+ mozilla::dom::time::InitializeDateCacheCleaner();
+}
+
+PMemoryReportRequestChild*
+ContentChild::AllocPMemoryReportRequestChild(const uint32_t& aGeneration,
+ const bool &aAnonymize,
+ const bool &aMinimizeMemoryUsage,
+ const MaybeFileDesc& aDMDFile)
+{
+ MemoryReportRequestChild *actor =
+ new MemoryReportRequestChild(aAnonymize, aDMDFile);
+ actor->AddRef();
+ return actor;
+}
+
+class HandleReportCallback final : public nsIHandleReportCallback
+{
+public:
+ NS_DECL_ISUPPORTS
+
+ explicit HandleReportCallback(MemoryReportRequestChild* aActor,
+ const nsACString& aProcess)
+ : mActor(aActor)
+ , mProcess(aProcess)
+ { }
+
+ NS_IMETHOD Callback(const nsACString& aProcess, const nsACString &aPath,
+ int32_t aKind, int32_t aUnits, int64_t aAmount,
+ const nsACString& aDescription,
+ nsISupports* aUnused) override
+ {
+ MemoryReport memreport(mProcess, nsCString(aPath), aKind, aUnits,
+ aAmount, nsCString(aDescription));
+ mActor->SendReport(memreport);
+ return NS_OK;
+ }
+private:
+ ~HandleReportCallback() {}
+
+ RefPtr<MemoryReportRequestChild> mActor;
+ const nsCString mProcess;
+};
+
+NS_IMPL_ISUPPORTS(
+ HandleReportCallback
+, nsIHandleReportCallback
+)
+
+class FinishReportingCallback final : public nsIFinishReportingCallback
+{
+public:
+ NS_DECL_ISUPPORTS
+
+ explicit FinishReportingCallback(MemoryReportRequestChild* aActor)
+ : mActor(aActor)
+ {
+ }
+
+ NS_IMETHOD Callback(nsISupports* aUnused) override
+ {
+ bool sent = PMemoryReportRequestChild::Send__delete__(mActor);
+ return sent ? NS_OK : NS_ERROR_FAILURE;
+ }
+
+private:
+ ~FinishReportingCallback() {}
+
+ RefPtr<MemoryReportRequestChild> mActor;
+};
+
+NS_IMPL_ISUPPORTS(
+ FinishReportingCallback
+, nsIFinishReportingCallback
+)
+
+bool
+ContentChild::RecvPMemoryReportRequestConstructor(
+ PMemoryReportRequestChild* aChild,
+ const uint32_t& aGeneration,
+ const bool& aAnonymize,
+ const bool& aMinimizeMemoryUsage,
+ const MaybeFileDesc& aDMDFile)
+{
+ MemoryReportRequestChild *actor =
+ static_cast<MemoryReportRequestChild*>(aChild);
+ DebugOnly<nsresult> rv;
+
+ if (aMinimizeMemoryUsage) {
+ nsCOMPtr<nsIMemoryReporterManager> mgr =
+ do_GetService("@mozilla.org/memory-reporter-manager;1");
+ rv = mgr->MinimizeMemoryUsage(actor);
+ // mgr will eventually call actor->Run()
+ } else {
+ rv = actor->Run();
+ }
+
+ // Bug 1295622: don't kill the process just because this failed.
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "actor operation failed");
+ return true;
+}
+
+NS_IMETHODIMP MemoryReportRequestChild::Run()
+{
+ ContentChild *child = static_cast<ContentChild*>(Manager());
+ nsCOMPtr<nsIMemoryReporterManager> mgr =
+ do_GetService("@mozilla.org/memory-reporter-manager;1");
+
+ nsCString process;
+ child->GetProcessName(process);
+ child->AppendProcessId(process);
+
+ // Run the reporters. The callback will turn each measurement into a
+ // MemoryReport.
+ RefPtr<HandleReportCallback> handleReport =
+ new HandleReportCallback(this, process);
+ RefPtr<FinishReportingCallback> finishReporting =
+ new FinishReportingCallback(this);
+
+ nsresult rv =
+ mgr->GetReportsForThisProcessExtended(handleReport, nullptr, mAnonymize,
+ FileDescriptorToFILE(mDMDFile, "wb"),
+ finishReporting, nullptr);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
+ "GetReportsForThisProcessExtended failed");
+ return rv;
+}
+
+bool
+ContentChild::DeallocPMemoryReportRequestChild(PMemoryReportRequestChild* actor)
+{
+ static_cast<MemoryReportRequestChild*>(actor)->Release();
+ return true;
+}
+
+PCycleCollectWithLogsChild*
+ContentChild::AllocPCycleCollectWithLogsChild(const bool& aDumpAllTraces,
+ const FileDescriptor& aGCLog,
+ const FileDescriptor& aCCLog)
+{
+ CycleCollectWithLogsChild* actor = new CycleCollectWithLogsChild(aGCLog, aCCLog);
+ // Return actor with refcount 0, which is safe because it has a non-XPCOM type.
+ return actor;
+}
+
+bool
+ContentChild::RecvPCycleCollectWithLogsConstructor(PCycleCollectWithLogsChild* aActor,
+ const bool& aDumpAllTraces,
+ const FileDescriptor& aGCLog,
+ const FileDescriptor& aCCLog)
+{
+ // Take a reference here, where the XPCOM type is regained.
+ RefPtr<CycleCollectWithLogsChild> sink = static_cast<CycleCollectWithLogsChild*>(aActor);
+ nsCOMPtr<nsIMemoryInfoDumper> dumper = do_GetService("@mozilla.org/memory-info-dumper;1");
+
+ dumper->DumpGCAndCCLogsToSink(aDumpAllTraces, sink);
+
+ // The actor's destructor is called when the last reference goes away...
+ return true;
+}
+
+bool
+ContentChild::DeallocPCycleCollectWithLogsChild(PCycleCollectWithLogsChild* /* aActor */)
+{
+ // ...so when we get here, there's nothing for us to do.
+ //
+ // Also, we're already in ~CycleCollectWithLogsChild (q.v.) at
+ // this point, so we shouldn't touch the actor in any case.
+ return true;
+}
+
+mozilla::plugins::PPluginModuleParent*
+ContentChild::AllocPPluginModuleParent(mozilla::ipc::Transport* aTransport,
+ base::ProcessId aOtherProcess)
+{
+ return plugins::PluginModuleContentParent::Initialize(aTransport, aOtherProcess);
+}
+
+PContentBridgeChild*
+ContentChild::AllocPContentBridgeChild(mozilla::ipc::Transport* aTransport,
+ base::ProcessId aOtherProcess)
+{
+ return ContentBridgeChild::Create(aTransport, aOtherProcess);
+}
+
+PContentBridgeParent*
+ContentChild::AllocPContentBridgeParent(mozilla::ipc::Transport* aTransport,
+ base::ProcessId aOtherProcess)
+{
+ MOZ_ASSERT(!mLastBridge);
+ mLastBridge = static_cast<ContentBridgeParent*>(
+ ContentBridgeParent::Create(aTransport, aOtherProcess));
+ return mLastBridge;
+}
+
+PGMPServiceChild*
+ContentChild::AllocPGMPServiceChild(mozilla::ipc::Transport* aTransport,
+ base::ProcessId aOtherProcess)
+{
+ return GMPServiceChild::Create(aTransport, aOtherProcess);
+}
+
+bool
+ContentChild::RecvGMPsChanged(nsTArray<GMPCapabilityData>&& capabilities)
+{
+ GeckoMediaPluginServiceChild::UpdateGMPCapabilities(Move(capabilities));
+ return true;
+}
+
+bool
+ContentChild::RecvInitRendering(Endpoint<PCompositorBridgeChild>&& aCompositor,
+ Endpoint<PImageBridgeChild>&& aImageBridge,
+ Endpoint<PVRManagerChild>&& aVRBridge,
+ Endpoint<PVideoDecoderManagerChild>&& aVideoManager)
+{
+ if (!CompositorBridgeChild::InitForContent(Move(aCompositor))) {
+ return false;
+ }
+ if (!ImageBridgeChild::InitForContent(Move(aImageBridge))) {
+ return false;
+ }
+ if (!gfx::VRManagerChild::InitForContent(Move(aVRBridge))) {
+ return false;
+ }
+ VideoDecoderManagerChild::InitForContent(Move(aVideoManager));
+ return true;
+}
+
+bool
+ContentChild::RecvReinitRendering(Endpoint<PCompositorBridgeChild>&& aCompositor,
+ Endpoint<PImageBridgeChild>&& aImageBridge,
+ Endpoint<PVRManagerChild>&& aVRBridge,
+ Endpoint<PVideoDecoderManagerChild>&& aVideoManager)
+{
+ nsTArray<RefPtr<TabChild>> tabs = TabChild::GetAll();
+
+ // Zap all the old layer managers we have lying around.
+ for (const auto& tabChild : tabs) {
+ if (tabChild->LayersId()) {
+ tabChild->InvalidateLayers();
+ }
+ }
+
+ // Re-establish singleton bridges to the compositor.
+ if (!CompositorBridgeChild::ReinitForContent(Move(aCompositor))) {
+ return false;
+ }
+ if (!ImageBridgeChild::ReinitForContent(Move(aImageBridge))) {
+ return false;
+ }
+ if (!gfx::VRManagerChild::ReinitForContent(Move(aVRBridge))) {
+ return false;
+ }
+
+ // Establish new PLayerTransactions.
+ for (const auto& tabChild : tabs) {
+ if (tabChild->LayersId()) {
+ tabChild->ReinitRendering();
+ }
+ }
+
+ VideoDecoderManagerChild::InitForContent(Move(aVideoManager));
+ return true;
+}
+
+PBackgroundChild*
+ContentChild::AllocPBackgroundChild(Transport* aTransport,
+ ProcessId aOtherProcess)
+{
+ return BackgroundChild::Alloc(aTransport, aOtherProcess);
+}
+
+PProcessHangMonitorChild*
+ContentChild::AllocPProcessHangMonitorChild(Transport* aTransport,
+ ProcessId aOtherProcess)
+{
+ return CreateHangMonitorChild(aTransport, aOtherProcess);
+}
+
+#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
+
+#include <stdlib.h>
+
+static bool
+GetAppPaths(nsCString &aAppPath, nsCString &aAppBinaryPath, nsCString &aAppDir)
+{
+ nsAutoCString appPath;
+ nsAutoCString appBinaryPath(
+ (CommandLine::ForCurrentProcess()->argv()[0]).c_str());
+
+ nsAutoCString::const_iterator start, end;
+ appBinaryPath.BeginReading(start);
+ appBinaryPath.EndReading(end);
+ if (RFindInReadable(NS_LITERAL_CSTRING(".app/Contents/MacOS/"), start, end)) {
+ end = start;
+ ++end; ++end; ++end; ++end;
+ appBinaryPath.BeginReading(start);
+ appPath.Assign(Substring(start, end));
+ } else {
+ return false;
+ }
+
+ nsCOMPtr<nsIFile> app, appBinary;
+ nsresult rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(appPath),
+ true, getter_AddRefs(app));
+ if (NS_FAILED(rv)) {
+ return false;
+ }
+ rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(appBinaryPath),
+ true, getter_AddRefs(appBinary));
+ if (NS_FAILED(rv)) {
+ return false;
+ }
+
+ nsCOMPtr<nsIFile> appDir;
+ nsCOMPtr<nsIProperties> dirSvc =
+ do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
+ if (!dirSvc) {
+ return false;
+ }
+ rv = dirSvc->Get(NS_XPCOM_CURRENT_PROCESS_DIR,
+ NS_GET_IID(nsIFile), getter_AddRefs(appDir));
+ if (NS_FAILED(rv)) {
+ return false;
+ }
+ bool exists;
+ rv = appDir->Exists(&exists);
+ if (NS_FAILED(rv) || !exists) {
+ return false;
+ }
+
+ bool isLink;
+ app->IsSymlink(&isLink);
+ if (isLink) {
+ app->GetNativeTarget(aAppPath);
+ } else {
+ app->GetNativePath(aAppPath);
+ }
+ appBinary->IsSymlink(&isLink);
+ if (isLink) {
+ appBinary->GetNativeTarget(aAppBinaryPath);
+ } else {
+ appBinary->GetNativePath(aAppBinaryPath);
+ }
+ appDir->IsSymlink(&isLink);
+ if (isLink) {
+ appDir->GetNativeTarget(aAppDir);
+ } else {
+ appDir->GetNativePath(aAppDir);
+ }
+
+ return true;
+}
+
+static bool
+StartMacOSContentSandbox()
+{
+ int sandboxLevel = Preferences::GetInt("security.sandbox.content.level");
+ if (sandboxLevel < 1) {
+ return false;
+ }
+
+ nsAutoCString appPath, appBinaryPath, appDir;
+ if (!GetAppPaths(appPath, appBinaryPath, appDir)) {
+ MOZ_CRASH("Error resolving child process path");
+ }
+
+ // During sandboxed content process startup, before reaching
+ // this point, NS_OS_TEMP_DIR is modified to refer to a sandbox-
+ // writable temporary directory
+ nsCOMPtr<nsIFile> tempDir;
+ nsresult rv = nsDirectoryService::gService->Get(NS_OS_TEMP_DIR,
+ NS_GET_IID(nsIFile), getter_AddRefs(tempDir));
+ if (NS_FAILED(rv)) {
+ MOZ_CRASH("Failed to get NS_OS_TEMP_DIR");
+ }
+
+ nsAutoCString tempDirPath;
+ tempDir->Normalize();
+ rv = tempDir->GetNativePath(tempDirPath);
+ if (NS_FAILED(rv)) {
+ MOZ_CRASH("Failed to get NS_OS_TEMP_DIR path");
+ }
+
+ nsCOMPtr<nsIFile> profileDir;
+ ContentChild::GetSingleton()->GetProfileDir(getter_AddRefs(profileDir));
+ nsCString profileDirPath;
+ if (profileDir) {
+ rv = profileDir->GetNativePath(profileDirPath);
+ if (NS_FAILED(rv) || profileDirPath.IsEmpty()) {
+ MOZ_CRASH("Failed to get profile path");
+ }
+ }
+
+ MacSandboxInfo info;
+ info.type = MacSandboxType_Content;
+ info.level = info.level = sandboxLevel;
+ info.appPath.assign(appPath.get());
+ info.appBinaryPath.assign(appBinaryPath.get());
+ info.appDir.assign(appDir.get());
+ info.appTempDir.assign(tempDirPath.get());
+
+ if (profileDir) {
+ info.hasSandboxedProfile = true;
+ info.profileDir.assign(profileDirPath.get());
+ } else {
+ info.hasSandboxedProfile = false;
+ }
+
+ std::string err;
+ if (!mozilla::StartMacSandbox(info, err)) {
+ NS_WARNING(err.c_str());
+ MOZ_CRASH("sandbox_init() failed");
+ }
+
+ return true;
+}
+#endif
+
+bool
+ContentChild::RecvSetProcessSandbox(const MaybeFileDesc& aBroker)
+{
+ // We may want to move the sandbox initialization somewhere else
+ // at some point; see bug 880808.
+#if defined(MOZ_CONTENT_SANDBOX)
+ bool sandboxEnabled = true;
+#if defined(XP_LINUX)
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19
+ // For B2G >= KitKat, sandboxing is mandatory; this has already
+ // been enforced by ContentParent::StartUp().
+ MOZ_ASSERT(SandboxInfo::Get().CanSandboxContent());
+#else
+ // Otherwise, sandboxing is best-effort.
+ if (!SandboxInfo::Get().CanSandboxContent()) {
+ sandboxEnabled = false;
+ } else {
+ // This triggers the initialization of cubeb, which needs to happen
+ // before seccomp is enabled (Bug 1259508). It also increases the startup
+ // time of the content process, because cubeb is usually initialized
+ // when it is actually needed. This call here is no longer required
+ // once Bug 1104619 (remoting audio) is resolved.
+ Unused << CubebUtils::GetCubebContext();
+ }
+
+#endif /* MOZ_WIDGET_GONK && ANDROID_VERSION >= 19 */
+ if (sandboxEnabled) {
+ int brokerFd = -1;
+ if (aBroker.type() == MaybeFileDesc::TFileDescriptor) {
+ auto fd = aBroker.get_FileDescriptor().ClonePlatformHandle();
+ brokerFd = fd.release();
+ // brokerFd < 0 means to allow direct filesystem access, so
+ // make absolutely sure that doesn't happen if the parent
+ // didn't intend it.
+ MOZ_RELEASE_ASSERT(brokerFd >= 0);
+ }
+ sandboxEnabled = SetContentProcessSandbox(brokerFd);
+ }
+#elif defined(XP_WIN)
+ mozilla::SandboxTarget::Instance()->StartSandbox();
+#elif defined(XP_MACOSX)
+ sandboxEnabled = StartMacOSContentSandbox();
+#endif
+
+#if defined(MOZ_CRASHREPORTER)
+ CrashReporter::AnnotateCrashReport(
+ NS_LITERAL_CSTRING("ContentSandboxEnabled"),
+ sandboxEnabled? NS_LITERAL_CSTRING("1") : NS_LITERAL_CSTRING("0"));
+#if defined(XP_LINUX) && !defined(OS_ANDROID)
+ nsAutoCString flagsString;
+ flagsString.AppendInt(SandboxInfo::Get().AsInteger());
+
+ CrashReporter::AnnotateCrashReport(
+ NS_LITERAL_CSTRING("ContentSandboxCapabilities"), flagsString);
+#endif /* XP_LINUX && !OS_ANDROID */
+#endif /* MOZ_CRASHREPORTER */
+#endif /* MOZ_CONTENT_SANDBOX */
+
+ return true;
+}
+
+bool
+ContentChild::RecvNotifyLayerAllocated(const dom::TabId& aTabId, const uint64_t& aLayersId)
+{
+ if (!CompositorBridgeChild::Get()->IPCOpen()) {
+ return true;
+ }
+
+ APZChild* apz = ContentProcessController::Create(aTabId);
+ return CompositorBridgeChild::Get()->SendPAPZConstructor(apz, aLayersId);
+}
+
+bool
+ContentChild::RecvSpeakerManagerNotify()
+{
+#ifdef MOZ_WIDGET_GONK
+ // Only notify the process which has the SpeakerManager instance.
+ RefPtr<SpeakerManagerService> service =
+ SpeakerManagerService::GetSpeakerManagerService();
+ if (service) {
+ service->Notify();
+ }
+ return true;
+#endif
+ return false;
+}
+
+bool
+ContentChild::RecvBidiKeyboardNotify(const bool& aIsLangRTL,
+ const bool& aHaveBidiKeyboards)
+{
+ // bidi is always of type PuppetBidiKeyboard* (because in the child, the only
+ // possible implementation of nsIBidiKeyboard is PuppetBidiKeyboard).
+ PuppetBidiKeyboard* bidi = static_cast<PuppetBidiKeyboard*>(nsContentUtils::GetBidiKeyboard());
+ if (bidi) {
+ bidi->SetBidiKeyboardInfo(aIsLangRTL, aHaveBidiKeyboards);
+ }
+ return true;
+}
+
+static CancelableRunnable* sFirstIdleTask;
+
+static void FirstIdle(void)
+{
+ MOZ_ASSERT(sFirstIdleTask);
+ sFirstIdleTask = nullptr;
+ ContentChild::GetSingleton()->SendFirstIdle();
+}
+
+mozilla::jsipc::PJavaScriptChild *
+ContentChild::AllocPJavaScriptChild()
+{
+ MOZ_ASSERT(ManagedPJavaScriptChild().IsEmpty());
+
+ return nsIContentChild::AllocPJavaScriptChild();
+}
+
+bool
+ContentChild::DeallocPJavaScriptChild(PJavaScriptChild *aChild)
+{
+ return nsIContentChild::DeallocPJavaScriptChild(aChild);
+}
+
+PBrowserChild*
+ContentChild::AllocPBrowserChild(const TabId& aTabId,
+ const IPCTabContext& aContext,
+ const uint32_t& aChromeFlags,
+ const ContentParentId& aCpID,
+ const bool& aIsForApp,
+ const bool& aIsForBrowser)
+{
+ return nsIContentChild::AllocPBrowserChild(aTabId,
+ aContext,
+ aChromeFlags,
+ aCpID,
+ aIsForApp,
+ aIsForBrowser);
+}
+
+bool
+ContentChild::SendPBrowserConstructor(PBrowserChild* aActor,
+ const TabId& aTabId,
+ const IPCTabContext& aContext,
+ const uint32_t& aChromeFlags,
+ const ContentParentId& aCpID,
+ const bool& aIsForApp,
+ const bool& aIsForBrowser)
+{
+ if (IsShuttingDown()) {
+ return false;
+ }
+
+ return PContentChild::SendPBrowserConstructor(aActor,
+ aTabId,
+ aContext,
+ aChromeFlags,
+ aCpID,
+ aIsForApp,
+ aIsForBrowser);
+}
+
+bool
+ContentChild::RecvPBrowserConstructor(PBrowserChild* aActor,
+ const TabId& aTabId,
+ const IPCTabContext& aContext,
+ const uint32_t& aChromeFlags,
+ const ContentParentId& aCpID,
+ const bool& aIsForApp,
+ const bool& aIsForBrowser)
+{
+ MOZ_ASSERT(!IsShuttingDown());
+
+ // This runs after AllocPBrowserChild() returns and the IPC machinery for this
+ // PBrowserChild has been set up.
+
+ nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+ if (os) {
+ nsITabChild* tc =
+ static_cast<nsITabChild*>(static_cast<TabChild*>(aActor));
+ os->NotifyObservers(tc, "tab-child-created", nullptr);
+ }
+
+ static bool hasRunOnce = false;
+ if (!hasRunOnce) {
+ hasRunOnce = true;
+
+ MOZ_ASSERT(!sFirstIdleTask);
+ RefPtr<CancelableRunnable> firstIdleTask = NewCancelableRunnableFunction(FirstIdle);
+ sFirstIdleTask = firstIdleTask;
+ MessageLoop::current()->PostIdleTask(firstIdleTask.forget());
+
+ // Redo InitProcessAttributes() when the app or browser is really
+ // launching so the attributes will be correct.
+ mID = aCpID;
+ mIsForApp = aIsForApp;
+ mIsForBrowser = aIsForBrowser;
+ InitProcessAttributes();
+ }
+
+ return true;
+}
+
+void
+ContentChild::GetAvailableDictionaries(InfallibleTArray<nsString>& aDictionaries)
+{
+ aDictionaries = mAvailableDictionaries;
+}
+
+PFileDescriptorSetChild*
+ContentChild::SendPFileDescriptorSetConstructor(const FileDescriptor& aFD)
+{
+ if (IsShuttingDown()) {
+ return nullptr;
+ }
+
+ return PContentChild::SendPFileDescriptorSetConstructor(aFD);
+}
+
+PFileDescriptorSetChild*
+ContentChild::AllocPFileDescriptorSetChild(const FileDescriptor& aFD)
+{
+ return nsIContentChild::AllocPFileDescriptorSetChild(aFD);
+}
+
+bool
+ContentChild::DeallocPFileDescriptorSetChild(PFileDescriptorSetChild* aActor)
+{
+ return nsIContentChild::DeallocPFileDescriptorSetChild(aActor);
+}
+
+bool
+ContentChild::DeallocPBrowserChild(PBrowserChild* aIframe)
+{
+ return nsIContentChild::DeallocPBrowserChild(aIframe);
+}
+
+PBlobChild*
+ContentChild::AllocPBlobChild(const BlobConstructorParams& aParams)
+{
+ return nsIContentChild::AllocPBlobChild(aParams);
+}
+
+mozilla::PRemoteSpellcheckEngineChild *
+ContentChild::AllocPRemoteSpellcheckEngineChild()
+{
+ MOZ_CRASH("Default Constructor for PRemoteSpellcheckEngineChild should never be called");
+ return nullptr;
+}
+
+bool
+ContentChild::DeallocPRemoteSpellcheckEngineChild(PRemoteSpellcheckEngineChild *child)
+{
+ delete child;
+ return true;
+}
+
+bool
+ContentChild::DeallocPBlobChild(PBlobChild* aActor)
+{
+ return nsIContentChild::DeallocPBlobChild(aActor);
+}
+
+PBlobChild*
+ContentChild::SendPBlobConstructor(PBlobChild* aActor,
+ const BlobConstructorParams& aParams)
+{
+ if (IsShuttingDown()) {
+ return nullptr;
+ }
+
+ return PContentChild::SendPBlobConstructor(aActor, aParams);
+}
+
+PPresentationChild*
+ContentChild::AllocPPresentationChild()
+{
+ MOZ_CRASH("We should never be manually allocating PPresentationChild actors");
+ return nullptr;
+}
+
+bool
+ContentChild::DeallocPPresentationChild(PPresentationChild* aActor)
+{
+ delete aActor;
+ return true;
+}
+
+PFlyWebPublishedServerChild*
+ContentChild::AllocPFlyWebPublishedServerChild(const nsString& name,
+ const FlyWebPublishOptions& params)
+{
+ MOZ_CRASH("We should never be manually allocating PFlyWebPublishedServerChild actors");
+ return nullptr;
+}
+
+bool
+ContentChild::DeallocPFlyWebPublishedServerChild(PFlyWebPublishedServerChild* aActor)
+{
+ RefPtr<FlyWebPublishedServerChild> actor =
+ dont_AddRef(static_cast<FlyWebPublishedServerChild*>(aActor));
+ return true;
+}
+
+bool
+ContentChild::RecvNotifyPresentationReceiverLaunched(PBrowserChild* aIframe,
+ const nsString& aSessionId)
+{
+ nsCOMPtr<nsIDocShell> docShell =
+ do_GetInterface(static_cast<TabChild*>(aIframe)->WebNavigation());
+ NS_WARNING_ASSERTION(docShell, "WebNavigation failed");
+
+ nsCOMPtr<nsIPresentationService> service =
+ do_GetService(PRESENTATION_SERVICE_CONTRACTID);
+ NS_WARNING_ASSERTION(service, "presentation service is missing");
+
+ Unused << NS_WARN_IF(NS_FAILED(static_cast<PresentationIPCService*>(service.get())->MonitorResponderLoading(aSessionId, docShell)));
+
+ return true;
+}
+
+bool
+ContentChild::RecvNotifyPresentationReceiverCleanUp(const nsString& aSessionId)
+{
+ nsCOMPtr<nsIPresentationService> service =
+ do_GetService(PRESENTATION_SERVICE_CONTRACTID);
+ NS_WARNING_ASSERTION(service, "presentation service is missing");
+
+ Unused << NS_WARN_IF(NS_FAILED(service->UntrackSessionInfo(aSessionId, nsIPresentationService::ROLE_RECEIVER)));
+
+ return true;
+}
+
+bool
+ContentChild::RecvNotifyEmptyHTTPCache()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+ obs->NotifyObservers(nullptr, "cacheservice:empty-cache", nullptr);
+ return true;
+}
+
+PCrashReporterChild*
+ContentChild::AllocPCrashReporterChild(const mozilla::dom::NativeThreadId& id,
+ const uint32_t& processType)
+{
+#ifdef MOZ_CRASHREPORTER
+ return new CrashReporterChild();
+#else
+ return nullptr;
+#endif
+}
+
+bool
+ContentChild::DeallocPCrashReporterChild(PCrashReporterChild* crashreporter)
+{
+ delete crashreporter;
+ return true;
+}
+
+PHalChild*
+ContentChild::AllocPHalChild()
+{
+ return CreateHalChild();
+}
+
+bool
+ContentChild::DeallocPHalChild(PHalChild* aHal)
+{
+ delete aHal;
+ return true;
+}
+
+devtools::PHeapSnapshotTempFileHelperChild*
+ContentChild::AllocPHeapSnapshotTempFileHelperChild()
+{
+ return devtools::HeapSnapshotTempFileHelperChild::Create();
+}
+
+bool
+ContentChild::DeallocPHeapSnapshotTempFileHelperChild(
+ devtools::PHeapSnapshotTempFileHelperChild* aHeapSnapshotHelper)
+{
+ delete aHeapSnapshotHelper;
+ return true;
+}
+
+PTestShellChild*
+ContentChild::AllocPTestShellChild()
+{
+ return new TestShellChild();
+}
+
+bool
+ContentChild::DeallocPTestShellChild(PTestShellChild* shell)
+{
+ delete shell;
+ return true;
+}
+
+jsipc::CPOWManager*
+ContentChild::GetCPOWManager()
+{
+ if (PJavaScriptChild* c = LoneManagedOrNullAsserts(ManagedPJavaScriptChild())) {
+ return CPOWManagerFor(c);
+ }
+ return CPOWManagerFor(SendPJavaScriptConstructor());
+}
+
+bool
+ContentChild::RecvPTestShellConstructor(PTestShellChild* actor)
+{
+ return true;
+}
+
+PNeckoChild*
+ContentChild::AllocPNeckoChild()
+{
+ return new NeckoChild();
+}
+
+bool
+ContentChild::DeallocPNeckoChild(PNeckoChild* necko)
+{
+ delete necko;
+ return true;
+}
+
+PPrintingChild*
+ContentChild::AllocPPrintingChild()
+{
+ // The ContentParent should never attempt to allocate the nsPrintingProxy,
+ // which implements PPrintingChild. Instead, the nsPrintingProxy service is
+ // requested and instantiated via XPCOM, and the constructor of
+ // nsPrintingProxy sets up the IPC connection.
+ MOZ_CRASH("Should never get here!");
+ return nullptr;
+}
+
+bool
+ContentChild::DeallocPPrintingChild(PPrintingChild* printing)
+{
+ return true;
+}
+
+PSendStreamChild*
+ContentChild::SendPSendStreamConstructor(PSendStreamChild* aActor)
+{
+ if (IsShuttingDown()) {
+ return nullptr;
+ }
+
+ return PContentChild::SendPSendStreamConstructor(aActor);
+}
+
+PSendStreamChild*
+ContentChild::AllocPSendStreamChild()
+{
+ return nsIContentChild::AllocPSendStreamChild();
+}
+
+bool
+ContentChild::DeallocPSendStreamChild(PSendStreamChild* aActor)
+{
+ return nsIContentChild::DeallocPSendStreamChild(aActor);
+}
+
+PScreenManagerChild*
+ContentChild::AllocPScreenManagerChild(uint32_t* aNumberOfScreens,
+ float* aSystemDefaultScale,
+ bool* aSuccess)
+{
+ // The ContentParent should never attempt to allocate the
+ // nsScreenManagerProxy. Instead, the nsScreenManagerProxy
+ // service is requested and instantiated via XPCOM, and the
+ // constructor of nsScreenManagerProxy sets up the IPC connection.
+ MOZ_CRASH("Should never get here!");
+ return nullptr;
+}
+
+bool
+ContentChild::DeallocPScreenManagerChild(PScreenManagerChild* aService)
+{
+ // nsScreenManagerProxy is AddRef'd in its constructor.
+ nsScreenManagerProxy *child = static_cast<nsScreenManagerProxy*>(aService);
+ child->Release();
+ return true;
+}
+
+PPSMContentDownloaderChild*
+ContentChild::AllocPPSMContentDownloaderChild(const uint32_t& aCertType)
+{
+ // NB: We don't need aCertType in the child actor.
+ RefPtr<PSMContentDownloaderChild> child = new PSMContentDownloaderChild();
+ return child.forget().take();
+}
+
+bool
+ContentChild::DeallocPPSMContentDownloaderChild(PPSMContentDownloaderChild* aListener)
+{
+ auto* listener = static_cast<PSMContentDownloaderChild*>(aListener);
+ RefPtr<PSMContentDownloaderChild> child = dont_AddRef(listener);
+ return true;
+}
+
+PExternalHelperAppChild*
+ContentChild::AllocPExternalHelperAppChild(const OptionalURIParams& uri,
+ const nsCString& aMimeContentType,
+ const nsCString& aContentDisposition,
+ const uint32_t& aContentDispositionHint,
+ const nsString& aContentDispositionFilename,
+ const bool& aForceSave,
+ const int64_t& aContentLength,
+ const bool& aWasFileChannel,
+ const OptionalURIParams& aReferrer,
+ PBrowserChild* aBrowser)
+{
+ ExternalHelperAppChild *child = new ExternalHelperAppChild();
+ child->AddRef();
+ return child;
+}
+
+bool
+ContentChild::DeallocPExternalHelperAppChild(PExternalHelperAppChild* aService)
+{
+ ExternalHelperAppChild *child = static_cast<ExternalHelperAppChild*>(aService);
+ child->Release();
+ return true;
+}
+
+PHandlerServiceChild*
+ContentChild::AllocPHandlerServiceChild()
+{
+ HandlerServiceChild* actor = new HandlerServiceChild();
+ actor->AddRef();
+ return actor;
+}
+
+bool ContentChild::DeallocPHandlerServiceChild(PHandlerServiceChild* aHandlerServiceChild)
+{
+ static_cast<HandlerServiceChild*>(aHandlerServiceChild)->Release();
+ return true;
+}
+
+media::PMediaChild*
+ContentChild::AllocPMediaChild()
+{
+ return media::AllocPMediaChild();
+}
+
+bool
+ContentChild::DeallocPMediaChild(media::PMediaChild *aActor)
+{
+ return media::DeallocPMediaChild(aActor);
+}
+
+PStorageChild*
+ContentChild::AllocPStorageChild()
+{
+ MOZ_CRASH("We should never be manually allocating PStorageChild actors");
+ return nullptr;
+}
+
+bool
+ContentChild::DeallocPStorageChild(PStorageChild* aActor)
+{
+ DOMStorageDBChild* child = static_cast<DOMStorageDBChild*>(aActor);
+ child->ReleaseIPDLReference();
+ return true;
+}
+
+PSpeechSynthesisChild*
+ContentChild::AllocPSpeechSynthesisChild()
+{
+#ifdef MOZ_WEBSPEECH
+ MOZ_CRASH("No one should be allocating PSpeechSynthesisChild actors");
+#else
+ return nullptr;
+#endif
+}
+
+bool
+ContentChild::DeallocPSpeechSynthesisChild(PSpeechSynthesisChild* aActor)
+{
+#ifdef MOZ_WEBSPEECH
+ delete aActor;
+ return true;
+#else
+ return false;
+#endif
+}
+
+PWebrtcGlobalChild *
+ContentChild::AllocPWebrtcGlobalChild()
+{
+#ifdef MOZ_WEBRTC
+ WebrtcGlobalChild *child = new WebrtcGlobalChild();
+ return child;
+#else
+ return nullptr;
+#endif
+}
+
+bool
+ContentChild::DeallocPWebrtcGlobalChild(PWebrtcGlobalChild *aActor)
+{
+#ifdef MOZ_WEBRTC
+ delete static_cast<WebrtcGlobalChild*>(aActor);
+ return true;
+#else
+ return false;
+#endif
+}
+
+
+bool
+ContentChild::RecvRegisterChrome(InfallibleTArray<ChromePackage>&& packages,
+ InfallibleTArray<SubstitutionMapping>&& resources,
+ InfallibleTArray<OverrideMapping>&& overrides,
+ const nsCString& locale,
+ const bool& reset)
+{
+ nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
+ nsChromeRegistryContent* chromeRegistry =
+ static_cast<nsChromeRegistryContent*>(registrySvc.get());
+ chromeRegistry->RegisterRemoteChrome(packages, resources, overrides,
+ locale, reset);
+ return true;
+}
+
+bool
+ContentChild::RecvRegisterChromeItem(const ChromeRegistryItem& item)
+{
+ nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
+ nsChromeRegistryContent* chromeRegistry =
+ static_cast<nsChromeRegistryContent*>(registrySvc.get());
+ switch (item.type()) {
+ case ChromeRegistryItem::TChromePackage:
+ chromeRegistry->RegisterPackage(item.get_ChromePackage());
+ break;
+
+ case ChromeRegistryItem::TOverrideMapping:
+ chromeRegistry->RegisterOverride(item.get_OverrideMapping());
+ break;
+
+ case ChromeRegistryItem::TSubstitutionMapping:
+ chromeRegistry->RegisterSubstitution(item.get_SubstitutionMapping());
+ break;
+
+ default:
+ MOZ_ASSERT(false, "bad chrome item");
+ return false;
+ }
+
+ return true;
+}
+
+bool
+ContentChild::RecvClearImageCache(const bool& privateLoader, const bool& chrome)
+{
+ imgLoader* loader = privateLoader ? imgLoader::PrivateBrowsingLoader() :
+ imgLoader::NormalLoader();
+
+ loader->ClearCache(chrome);
+ return true;
+}
+
+bool
+ContentChild::RecvSetOffline(const bool& offline)
+{
+ nsCOMPtr<nsIIOService> io (do_GetIOService());
+ NS_ASSERTION(io, "IO Service can not be null");
+
+ io->SetOffline(offline);
+
+ return true;
+}
+
+bool
+ContentChild::RecvSetConnectivity(const bool& connectivity)
+{
+ nsCOMPtr<nsIIOService> io(do_GetIOService());
+ nsCOMPtr<nsIIOServiceInternal> ioInternal(do_QueryInterface(io));
+ NS_ASSERTION(ioInternal, "IO Service can not be null");
+
+ ioInternal->SetConnectivity(connectivity);
+
+ return true;
+}
+
+bool
+ContentChild::RecvSetCaptivePortalState(const int32_t& aState)
+{
+ nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CID);
+ if (!cps) {
+ return true;
+ }
+
+ mozilla::net::CaptivePortalService *portal =
+ static_cast<mozilla::net::CaptivePortalService*>(cps.get());
+ portal->SetStateInChild(aState);
+
+ return true;
+}
+
+void
+ContentChild::ActorDestroy(ActorDestroyReason why)
+{
+ if (mForceKillTimer) {
+ mForceKillTimer->Cancel();
+ mForceKillTimer = nullptr;
+ }
+
+ if (AbnormalShutdown == why) {
+ NS_WARNING("shutting down early because of crash!");
+ ProcessChild::QuickExit();
+ }
+
+#ifndef NS_FREE_PERMANENT_DATA
+ // In release builds, there's no point in the content process
+ // going through the full XPCOM shutdown path, because it doesn't
+ // keep persistent state.
+ ProcessChild::QuickExit();
+#else
+ if (sFirstIdleTask) {
+ sFirstIdleTask->Cancel();
+ }
+
+ nsHostObjectProtocolHandler::RemoveDataEntries();
+
+ mAlertObservers.Clear();
+
+ mIdleObservers.Clear();
+
+ nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
+ if (svc) {
+ svc->UnregisterListener(mConsoleListener);
+ mConsoleListener->mChild = nullptr;
+ }
+ mIsAlive = false;
+
+ XRE_ShutdownChildProcess();
+#endif // NS_FREE_PERMANENT_DATA
+}
+
+void
+ContentChild::ProcessingError(Result aCode, const char* aReason)
+{
+ switch (aCode) {
+ case MsgDropped:
+ NS_WARNING("MsgDropped in ContentChild");
+ return;
+
+ case MsgNotKnown:
+ case MsgNotAllowed:
+ case MsgPayloadError:
+ case MsgProcessingError:
+ case MsgRouteError:
+ case MsgValueError:
+ break;
+
+ default:
+ NS_RUNTIMEABORT("not reached");
+ }
+
+#if defined(MOZ_CRASHREPORTER) && !defined(MOZ_B2G)
+ if (PCrashReporterChild* c = LoneManagedOrNullAsserts(ManagedPCrashReporterChild())) {
+ CrashReporterChild* crashReporter =
+ static_cast<CrashReporterChild*>(c);
+ nsDependentCString reason(aReason);
+ crashReporter->SendAnnotateCrashReport(
+ NS_LITERAL_CSTRING("ipc_channel_error"),
+ reason);
+ }
+#endif
+ NS_RUNTIMEABORT("Content child abort due to IPC error");
+}
+
+nsresult
+ContentChild::AddRemoteAlertObserver(const nsString& aData,
+ nsIObserver* aObserver)
+{
+ NS_ASSERTION(aObserver, "Adding a null observer?");
+ mAlertObservers.AppendElement(new AlertObserver(aObserver, aData));
+ return NS_OK;
+}
+
+bool
+ContentChild::RecvPreferenceUpdate(const PrefSetting& aPref)
+{
+ Preferences::SetPreference(aPref);
+ return true;
+}
+
+bool
+ContentChild::RecvVarUpdate(const GfxVarUpdate& aVar)
+{
+ gfx::gfxVars::ApplyUpdate(aVar);
+ return true;
+}
+
+bool
+ContentChild::RecvDataStoragePut(const nsString& aFilename,
+ const DataStorageItem& aItem)
+{
+ RefPtr<DataStorage> storage = DataStorage::GetIfExists(aFilename);
+ if (storage) {
+ storage->Put(aItem.key(), aItem.value(), aItem.type());
+ }
+ return true;
+}
+
+bool
+ContentChild::RecvDataStorageRemove(const nsString& aFilename,
+ const nsCString& aKey,
+ const DataStorageType& aType)
+{
+ RefPtr<DataStorage> storage = DataStorage::GetIfExists(aFilename);
+ if (storage) {
+ storage->Remove(aKey, aType);
+ }
+ return true;
+}
+
+bool
+ContentChild::RecvDataStorageClear(const nsString& aFilename)
+{
+ RefPtr<DataStorage> storage = DataStorage::GetIfExists(aFilename);
+ if (storage) {
+ storage->Clear();
+ }
+ return true;
+}
+
+bool
+ContentChild::RecvNotifyAlertsObserver(const nsCString& aType, const nsString& aData)
+{
+ for (uint32_t i = 0; i < mAlertObservers.Length();
+ /*we mutate the array during the loop; ++i iff no mutation*/) {
+ AlertObserver* observer = mAlertObservers[i];
+ if (observer->Observes(aData) && observer->Notify(aType)) {
+ // if aType == alertfinished, this alert is done. we can
+ // remove the observer.
+ if (aType.Equals(nsDependentCString("alertfinished"))) {
+ mAlertObservers.RemoveElementAt(i);
+ continue;
+ }
+ }
+ ++i;
+ }
+ return true;
+}
+
+bool
+ContentChild::RecvNotifyVisited(const URIParams& aURI)
+{
+ nsCOMPtr<nsIURI> newURI = DeserializeURI(aURI);
+ if (!newURI) {
+ return false;
+ }
+ nsCOMPtr<IHistory> history = services::GetHistoryService();
+ if (history) {
+ history->NotifyVisited(newURI);
+ }
+ return true;
+}
+
+bool
+ContentChild::RecvLoadProcessScript(const nsString& aURL)
+{
+ ProcessGlobal* global = ProcessGlobal::Get();
+ global->LoadScript(aURL);
+ return true;
+}
+
+bool
+ContentChild::RecvAsyncMessage(const nsString& aMsg,
+ InfallibleTArray<CpowEntry>&& aCpows,
+ const IPC::Principal& aPrincipal,
+ const ClonedMessageData& aData)
+{
+ RefPtr<nsFrameMessageManager> cpm =
+ nsFrameMessageManager::GetChildProcessManager();
+ if (cpm) {
+ StructuredCloneData data;
+ ipc::UnpackClonedMessageDataForChild(aData, data);
+ CrossProcessCpowHolder cpows(this, aCpows);
+ cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()),
+ nullptr, aMsg, false, &data, &cpows, aPrincipal,
+ nullptr);
+ }
+ return true;
+}
+
+bool
+ContentChild::RecvGeolocationUpdate(const GeoPosition& somewhere)
+{
+ nsCOMPtr<nsIGeolocationUpdate> gs =
+ do_GetService("@mozilla.org/geolocation/service;1");
+ if (!gs) {
+ return true;
+ }
+ nsCOMPtr<nsIDOMGeoPosition> position = somewhere;
+ gs->Update(position);
+ return true;
+}
+
+bool
+ContentChild::RecvGeolocationError(const uint16_t& errorCode)
+{
+ nsCOMPtr<nsIGeolocationUpdate> gs =
+ do_GetService("@mozilla.org/geolocation/service;1");
+ if (!gs) {
+ return true;
+ }
+ gs->NotifyError(errorCode);
+ return true;
+}
+
+bool
+ContentChild::RecvUpdateDictionaryList(InfallibleTArray<nsString>&& aDictionaries)
+{
+ mAvailableDictionaries = aDictionaries;
+ mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking();
+ return true;
+}
+
+bool
+ContentChild::RecvAddPermission(const IPC::Permission& permission)
+{
+#if MOZ_PERMISSIONS
+ nsCOMPtr<nsIPermissionManager> permissionManagerIface =
+ services::GetPermissionManager();
+ nsPermissionManager* permissionManager =
+ static_cast<nsPermissionManager*>(permissionManagerIface.get());
+ MOZ_ASSERT(permissionManager,
+ "We have no permissionManager in the Content process !");
+
+ // note we do not need to force mUserContextId to the default here because
+ // the permission manager does that internally.
+ nsAutoCString originNoSuffix;
+ PrincipalOriginAttributes attrs;
+ bool success = attrs.PopulateFromOrigin(permission.origin, originNoSuffix);
+ NS_ENSURE_TRUE(success, false);
+
+ nsCOMPtr<nsIURI> uri;
+ nsresult rv = NS_NewURI(getter_AddRefs(uri), originNoSuffix);
+ NS_ENSURE_SUCCESS(rv, true);
+
+ nsCOMPtr<nsIPrincipal> principal = mozilla::BasePrincipal::CreateCodebasePrincipal(uri, attrs);
+
+ // child processes don't care about modification time.
+ int64_t modificationTime = 0;
+
+ permissionManager->AddInternal(principal,
+ nsCString(permission.type),
+ permission.capability,
+ 0,
+ permission.expireType,
+ permission.expireTime,
+ modificationTime,
+ nsPermissionManager::eNotify,
+ nsPermissionManager::eNoDBOperation);
+#endif
+
+ return true;
+}
+
+bool
+ContentChild::RecvFlushMemory(const nsString& reason)
+{
+ nsCOMPtr<nsIObserverService> os =
+ mozilla::services::GetObserverService();
+ if (os) {
+ os->NotifyObservers(nullptr, "memory-pressure", reason.get());
+ }
+ return true;
+}
+
+bool
+ContentChild::RecvActivateA11y(const uint32_t& aMsaaID)
+{
+#ifdef ACCESSIBILITY
+#ifdef XP_WIN
+ MOZ_ASSERT(aMsaaID != 0);
+ mMsaaID = aMsaaID;
+#endif // XP_WIN
+
+ // Start accessibility in content process if it's running in chrome
+ // process.
+ GetOrCreateAccService(nsAccessibilityService::eMainProcess);
+#endif // ACCESSIBILITY
+ return true;
+}
+
+bool
+ContentChild::RecvShutdownA11y()
+{
+#ifdef ACCESSIBILITY
+ // Try to shutdown accessibility in content process if it's shutting down in
+ // chrome process.
+ MaybeShutdownAccService(nsAccessibilityService::eMainProcess);
+#endif
+ return true;
+}
+
+bool
+ContentChild::RecvGarbageCollect()
+{
+ // Rebroadcast the "child-gc-request" so that workers will GC.
+ nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+ if (obs) {
+ obs->NotifyObservers(nullptr, "child-gc-request", nullptr);
+ }
+ nsJSContext::GarbageCollectNow(JS::gcreason::DOM_IPC);
+ return true;
+}
+
+bool
+ContentChild::RecvCycleCollect()
+{
+ // Rebroadcast the "child-cc-request" so that workers will CC.
+ nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+ if (obs) {
+ obs->NotifyObservers(nullptr, "child-cc-request", nullptr);
+ }
+ nsJSContext::CycleCollectNow();
+ return true;
+}
+
+static void
+PreloadSlowThings()
+{
+ // This fetches and creates all the built-in stylesheets.
+ //
+ // XXXheycam In the future we might want to preload the Servo-flavoured
+ // UA sheets too, but for now that will be a waste of time.
+ nsLayoutStylesheetCache::For(StyleBackendType::Gecko)->UserContentSheet();
+
+ TabChild::PreloadSlowThings();
+
+}
+
+bool
+ContentChild::RecvAppInfo(const nsCString& version, const nsCString& buildID,
+ const nsCString& name, const nsCString& UAName,
+ const nsCString& ID, const nsCString& vendor)
+{
+ mAppInfo.version.Assign(version);
+ mAppInfo.buildID.Assign(buildID);
+ mAppInfo.name.Assign(name);
+ mAppInfo.UAName.Assign(UAName);
+ mAppInfo.ID.Assign(ID);
+ mAppInfo.vendor.Assign(vendor);
+
+ return true;
+}
+
+bool
+ContentChild::RecvAppInit()
+{
+ if (!Preferences::GetBool("dom.ipc.processPrelaunch.enabled", false)) {
+ return true;
+ }
+
+ // If we're part of the mozbrowser machinery, go ahead and start
+ // preloading things. We can only do this for mozbrowser because
+ // PreloadSlowThings() may set the docshell of the first TabChild
+ // inactive, and we can only safely restore it to active from
+ // BrowserElementChild.js.
+ if (mIsForApp || mIsForBrowser) {
+ PreloadSlowThings();
+ }
+
+ return true;
+}
+
+bool
+ContentChild::RecvInitServiceWorkers(const ServiceWorkerConfiguration& aConfig)
+{
+ RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+ if (!swm) {
+ // browser shutdown began
+ return true;
+ }
+ swm->LoadRegistrations(aConfig.serviceWorkerRegistrations());
+ return true;
+}
+
+bool
+ContentChild::RecvInitBlobURLs(nsTArray<BlobURLRegistrationData>&& aRegistrations)
+{
+ for (uint32_t i = 0; i < aRegistrations.Length(); ++i) {
+ BlobURLRegistrationData& registration = aRegistrations[i];
+ RefPtr<BlobImpl> blobImpl =
+ static_cast<BlobChild*>(registration.blobChild())->GetBlobImpl();
+ MOZ_ASSERT(blobImpl);
+
+ nsHostObjectProtocolHandler::AddDataEntry(registration.url(),
+ registration.principal(),
+ blobImpl);
+ }
+
+ return true;
+}
+
+bool
+ContentChild::RecvLastPrivateDocShellDestroyed()
+{
+ nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+ obs->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
+ return true;
+}
+
+bool
+ContentChild::RecvVolumes(nsTArray<VolumeInfo>&& aVolumes)
+{
+#ifdef MOZ_WIDGET_GONK
+ RefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
+ if (vs) {
+ vs->RecvVolumesFromParent(aVolumes);
+ }
+#endif
+ return true;
+}
+
+bool
+ContentChild::RecvFileSystemUpdate(const nsString& aFsName,
+ const nsString& aVolumeName,
+ const int32_t& aState,
+ const int32_t& aMountGeneration,
+ const bool& aIsMediaPresent,
+ const bool& aIsSharing,
+ const bool& aIsFormatting,
+ const bool& aIsFake,
+ const bool& aIsUnmounting,
+ const bool& aIsRemovable,
+ const bool& aIsHotSwappable)
+{
+#ifdef MOZ_WIDGET_GONK
+ RefPtr<nsVolume> volume = new nsVolume(aFsName, aVolumeName, aState,
+ aMountGeneration, aIsMediaPresent,
+ aIsSharing, aIsFormatting, aIsFake,
+ aIsUnmounting, aIsRemovable, aIsHotSwappable);
+
+ RefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
+ if (vs) {
+ vs->UpdateVolume(volume);
+ }
+#else
+ // Remove warnings about unused arguments
+ Unused << aFsName;
+ Unused << aVolumeName;
+ Unused << aState;
+ Unused << aMountGeneration;
+ Unused << aIsMediaPresent;
+ Unused << aIsSharing;
+ Unused << aIsFormatting;
+ Unused << aIsFake;
+ Unused << aIsUnmounting;
+ Unused << aIsRemovable;
+ Unused << aIsHotSwappable;
+#endif
+ return true;
+}
+
+bool
+ContentChild::RecvVolumeRemoved(const nsString& aFsName)
+{
+#ifdef MOZ_WIDGET_GONK
+ RefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
+ if (vs) {
+ vs->RemoveVolumeByName(aFsName);
+ }
+#else
+ // Remove warnings about unused arguments
+ Unused << aFsName;
+#endif
+ return true;
+}
+
+bool
+ContentChild::RecvNotifyProcessPriorityChanged(
+ const hal::ProcessPriority& aPriority)
+{
+ nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+ NS_ENSURE_TRUE(os, true);
+
+ RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
+ props->SetPropertyAsInt32(NS_LITERAL_STRING("priority"),
+ static_cast<int32_t>(aPriority));
+
+ os->NotifyObservers(static_cast<nsIPropertyBag2*>(props),
+ "ipc:process-priority-changed", nullptr);
+ return true;
+}
+
+bool
+ContentChild::RecvMinimizeMemoryUsage()
+{
+ nsCOMPtr<nsIMemoryReporterManager> mgr =
+ do_GetService("@mozilla.org/memory-reporter-manager;1");
+ NS_ENSURE_TRUE(mgr, true);
+
+ Unused << mgr->MinimizeMemoryUsage(/* callback = */ nullptr);
+ return true;
+}
+
+bool
+ContentChild::RecvNotifyPhoneStateChange(const nsString& aState)
+{
+ nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+ if (os) {
+ os->NotifyObservers(nullptr, "phone-state-changed", aState.get());
+ }
+ return true;
+}
+
+void
+ContentChild::AddIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS)
+{
+ MOZ_ASSERT(aObserver, "null idle observer");
+ // Make sure aObserver isn't released while we wait for the parent
+ aObserver->AddRef();
+ SendAddIdleObserver(reinterpret_cast<uint64_t>(aObserver), aIdleTimeInS);
+ mIdleObservers.PutEntry(aObserver);
+}
+
+void
+ContentChild::RemoveIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS)
+{
+ MOZ_ASSERT(aObserver, "null idle observer");
+ SendRemoveIdleObserver(reinterpret_cast<uint64_t>(aObserver), aIdleTimeInS);
+ aObserver->Release();
+ mIdleObservers.RemoveEntry(aObserver);
+}
+
+bool
+ContentChild::RecvNotifyIdleObserver(const uint64_t& aObserver,
+ const nsCString& aTopic,
+ const nsString& aTimeStr)
+{
+ nsIObserver* observer = reinterpret_cast<nsIObserver*>(aObserver);
+ if (mIdleObservers.Contains(observer)) {
+ observer->Observe(nullptr, aTopic.get(), aTimeStr.get());
+ } else {
+ NS_WARNING("Received notification for an idle observer that was removed.");
+ }
+ return true;
+}
+
+bool
+ContentChild::RecvLoadAndRegisterSheet(const URIParams& aURI, const uint32_t& aType)
+{
+ nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
+ if (!uri) {
+ return true;
+ }
+
+ nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
+ if (sheetService) {
+ sheetService->LoadAndRegisterSheet(uri, aType);
+ }
+
+ return true;
+}
+
+bool
+ContentChild::RecvUnregisterSheet(const URIParams& aURI, const uint32_t& aType)
+{
+ nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
+ if (!uri) {
+ return true;
+ }
+
+ nsStyleSheetService *sheetService = nsStyleSheetService::GetInstance();
+ if (sheetService) {
+ sheetService->UnregisterSheet(uri, aType);
+ }
+
+ return true;
+}
+
+POfflineCacheUpdateChild*
+ContentChild::AllocPOfflineCacheUpdateChild(const URIParams& manifestURI,
+ const URIParams& documentURI,
+ const PrincipalInfo& aLoadingPrincipalInfo,
+ const bool& stickDocument)
+{
+ NS_RUNTIMEABORT("unused");
+ return nullptr;
+}
+
+bool
+ContentChild::DeallocPOfflineCacheUpdateChild(POfflineCacheUpdateChild* actor)
+{
+ OfflineCacheUpdateChild* offlineCacheUpdate =
+ static_cast<OfflineCacheUpdateChild*>(actor);
+ NS_RELEASE(offlineCacheUpdate);
+ return true;
+}
+
+bool
+ContentChild::RecvStartProfiler(const ProfilerInitParams& params)
+{
+ nsTArray<const char*> featureArray;
+ for (size_t i = 0; i < params.features().Length(); ++i) {
+ featureArray.AppendElement(params.features()[i].get());
+ }
+
+ nsTArray<const char*> threadNameFilterArray;
+ for (size_t i = 0; i < params.threadFilters().Length(); ++i) {
+ threadNameFilterArray.AppendElement(params.threadFilters()[i].get());
+ }
+
+ profiler_start(params.entries(), params.interval(),
+ featureArray.Elements(), featureArray.Length(),
+ threadNameFilterArray.Elements(),
+ threadNameFilterArray.Length());
+
+ return true;
+}
+
+bool
+ContentChild::RecvStopProfiler()
+{
+ profiler_stop();
+ return true;
+}
+
+bool
+ContentChild::RecvPauseProfiler(const bool& aPause)
+{
+ if (aPause) {
+ profiler_pause();
+ } else {
+ profiler_resume();
+ }
+
+ return true;
+}
+
+bool
+ContentChild::RecvGatherProfile()
+{
+ nsCString profileCString;
+ UniquePtr<char[]> profile = profiler_get_profile();
+ if (profile) {
+ profileCString = nsCString(profile.get(), strlen(profile.get()));
+ } else {
+ profileCString = EmptyCString();
+ }
+
+ Unused << SendProfile(profileCString);
+ return true;
+}
+
+bool
+ContentChild::RecvLoadPluginResult(const uint32_t& aPluginId,
+ const bool& aResult)
+{
+ nsresult rv;
+ bool finalResult = aResult && SendConnectPluginBridge(aPluginId, &rv) &&
+ NS_SUCCEEDED(rv);
+ plugins::PluginModuleContentParent::OnLoadPluginResult(aPluginId,
+ finalResult);
+ return true;
+}
+
+bool
+ContentChild::RecvAssociatePluginId(const uint32_t& aPluginId,
+ const base::ProcessId& aProcessId)
+{
+ plugins::PluginModuleContentParent::AssociatePluginId(aPluginId, aProcessId);
+ return true;
+}
+
+bool
+ContentChild::RecvDomainSetChanged(const uint32_t& aSetType,
+ const uint32_t& aChangeType,
+ const OptionalURIParams& aDomain)
+{
+ if (aChangeType == ACTIVATE_POLICY) {
+ if (mPolicy) {
+ return true;
+ }
+ nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
+ MOZ_ASSERT(ssm);
+ ssm->ActivateDomainPolicyInternal(getter_AddRefs(mPolicy));
+ return !!mPolicy;
+ } else if (!mPolicy) {
+ MOZ_ASSERT_UNREACHABLE("If the domain policy is not active yet,"
+ " the first message should be ACTIVATE_POLICY");
+ return false;
+ }
+
+ NS_ENSURE_TRUE(mPolicy, false);
+
+ if (aChangeType == DEACTIVATE_POLICY) {
+ mPolicy->Deactivate();
+ mPolicy = nullptr;
+ return true;
+ }
+
+ nsCOMPtr<nsIDomainSet> set;
+ switch(aSetType) {
+ case BLACKLIST:
+ mPolicy->GetBlacklist(getter_AddRefs(set));
+ break;
+ case SUPER_BLACKLIST:
+ mPolicy->GetSuperBlacklist(getter_AddRefs(set));
+ break;
+ case WHITELIST:
+ mPolicy->GetWhitelist(getter_AddRefs(set));
+ break;
+ case SUPER_WHITELIST:
+ mPolicy->GetSuperWhitelist(getter_AddRefs(set));
+ break;
+ default:
+ NS_NOTREACHED("Unexpected setType");
+ return false;
+ }
+
+ MOZ_ASSERT(set);
+
+ nsCOMPtr<nsIURI> uri = DeserializeURI(aDomain);
+
+ switch(aChangeType) {
+ case ADD_DOMAIN:
+ NS_ENSURE_TRUE(uri, false);
+ set->Add(uri);
+ break;
+ case REMOVE_DOMAIN:
+ NS_ENSURE_TRUE(uri, false);
+ set->Remove(uri);
+ break;
+ case CLEAR_DOMAINS:
+ set->Clear();
+ break;
+ default:
+ NS_NOTREACHED("Unexpected changeType");
+ return false;
+ }
+
+ return true;
+}
+
+void
+ContentChild::StartForceKillTimer()
+{
+ if (mForceKillTimer) {
+ return;
+ }
+
+ int32_t timeoutSecs = Preferences::GetInt("dom.ipc.tabs.shutdownTimeoutSecs", 5);
+ if (timeoutSecs > 0) {
+ mForceKillTimer = do_CreateInstance("@mozilla.org/timer;1");
+ MOZ_ASSERT(mForceKillTimer);
+ mForceKillTimer->InitWithFuncCallback(ContentChild::ForceKillTimerCallback,
+ this,
+ timeoutSecs * 1000,
+ nsITimer::TYPE_ONE_SHOT);
+ }
+}
+
+/* static */ void
+ContentChild::ForceKillTimerCallback(nsITimer* aTimer, void* aClosure)
+{
+ ProcessChild::QuickExit();
+}
+
+bool
+ContentChild::RecvShutdown()
+{
+ // If we receive the shutdown message from within a nested event loop, we want
+ // to wait for that event loop to finish. Otherwise we could prematurely
+ // terminate an "unload" or "pagehide" event handler (which might be doing a
+ // sync XHR, for example).
+#if defined(MOZ_CRASHREPORTER)
+ CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCShutdownState"),
+ NS_LITERAL_CSTRING("RecvShutdown"));
+#endif
+ nsCOMPtr<nsIThread> thread;
+ nsresult rv = NS_GetMainThread(getter_AddRefs(thread));
+ if (NS_SUCCEEDED(rv) && thread) {
+ RefPtr<nsThread> mainThread(thread.forget().downcast<nsThread>());
+ if (mainThread->RecursionDepth() > 1) {
+ // We're in a nested event loop. Let's delay for an arbitrary period of
+ // time (100ms) in the hopes that the event loop will have finished by
+ // then.
+ MessageLoop::current()->PostDelayedTask(
+ NewRunnableMethod(this, &ContentChild::RecvShutdown), 100);
+ return true;
+ }
+ }
+
+ mShuttingDown = true;
+
+ if (mPolicy) {
+ mPolicy->Deactivate();
+ mPolicy = nullptr;
+ }
+
+ nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+ if (os) {
+ os->NotifyObservers(static_cast<nsIContentChild*>(this),
+ "content-child-shutdown", nullptr);
+ }
+
+#if defined(XP_WIN)
+ mozilla::widget::StopAudioSession();
+#endif
+
+ GetIPCChannel()->SetAbortOnError(false);
+
+#ifdef MOZ_ENABLE_PROFILER_SPS
+ if (profiler_is_active()) {
+ // We're shutting down while we were profiling. Send the
+ // profile up to the parent so that we don't lose this
+ // information.
+ Unused << RecvGatherProfile();
+ }
+#endif
+
+ // Start a timer that will insure we quickly exit after a reasonable
+ // period of time. Prevents shutdown hangs after our connection to the
+ // parent closes.
+ StartForceKillTimer();
+
+#if defined(MOZ_CRASHREPORTER)
+ CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCShutdownState"),
+ NS_LITERAL_CSTRING("SendFinishShutdown"));
+#endif
+ // Ignore errors here. If this fails, the parent will kill us after a
+ // timeout.
+ Unused << SendFinishShutdown();
+ return true;
+}
+
+PBrowserOrId
+ContentChild::GetBrowserOrId(TabChild* aTabChild)
+{
+ if (!aTabChild ||
+ this == aTabChild->Manager()) {
+ return PBrowserOrId(aTabChild);
+ }
+ else {
+ return PBrowserOrId(aTabChild->GetTabId());
+ }
+}
+
+bool
+ContentChild::RecvUpdateWindow(const uintptr_t& aChildId)
+{
+#if defined(XP_WIN)
+ NS_ASSERTION(aChildId, "Expected child hwnd value for remote plugin instance.");
+ mozilla::plugins::PluginInstanceParent* parentInstance =
+ mozilla::plugins::PluginInstanceParent::LookupPluginInstanceByID(aChildId);
+ if (parentInstance) {
+ // sync! update call to the plugin instance that forces the
+ // plugin to paint its child window.
+ parentInstance->CallUpdateWindow();
+ }
+ return true;
+#else
+ MOZ_ASSERT(false, "ContentChild::RecvUpdateWindow calls unexpected on this platform.");
+ return false;
+#endif
+}
+
+PContentPermissionRequestChild*
+ContentChild::AllocPContentPermissionRequestChild(const InfallibleTArray<PermissionRequest>& aRequests,
+ const IPC::Principal& aPrincipal,
+ const TabId& aTabId)
+{
+ NS_RUNTIMEABORT("unused");
+ return nullptr;
+}
+
+bool
+ContentChild::DeallocPContentPermissionRequestChild(PContentPermissionRequestChild* actor)
+{
+ nsContentPermissionUtils::NotifyRemoveContentPermissionRequestChild(actor);
+ auto child = static_cast<RemotePermissionRequest*>(actor);
+ child->IPDLRelease();
+ return true;
+}
+
+PWebBrowserPersistDocumentChild*
+ContentChild::AllocPWebBrowserPersistDocumentChild(PBrowserChild* aBrowser,
+ const uint64_t& aOuterWindowID)
+{
+ return new WebBrowserPersistDocumentChild();
+}
+
+bool
+ContentChild::RecvPWebBrowserPersistDocumentConstructor(PWebBrowserPersistDocumentChild *aActor,
+ PBrowserChild* aBrowser,
+ const uint64_t& aOuterWindowID)
+{
+ if (NS_WARN_IF(!aBrowser)) {
+ return false;
+ }
+ nsCOMPtr<nsIDocument> rootDoc =
+ static_cast<TabChild*>(aBrowser)->GetDocument();
+ nsCOMPtr<nsIDocument> foundDoc;
+ if (aOuterWindowID) {
+ foundDoc = nsContentUtils::GetSubdocumentWithOuterWindowId(rootDoc, aOuterWindowID);
+ } else {
+ foundDoc = rootDoc;
+ }
+
+ if (!foundDoc) {
+ aActor->SendInitFailure(NS_ERROR_NO_CONTENT);
+ } else {
+ static_cast<WebBrowserPersistDocumentChild*>(aActor)->Start(foundDoc);
+ }
+ return true;
+}
+
+bool
+ContentChild::DeallocPWebBrowserPersistDocumentChild(PWebBrowserPersistDocumentChild* aActor)
+{
+ delete aActor;
+ return true;
+}
+
+bool
+ContentChild::RecvSetAudioSessionData(const nsID& aId,
+ const nsString& aDisplayName,
+ const nsString& aIconPath)
+{
+#if defined(XP_WIN)
+ if (NS_FAILED(mozilla::widget::RecvAudioSessionData(aId, aDisplayName,
+ aIconPath))) {
+ return true;
+ }
+
+ // Ignore failures here; we can't really do anything about them
+ mozilla::widget::StartAudioSession();
+ return true;
+#else
+ NS_RUNTIMEABORT("Not Reached!");
+ return false;
+#endif
+}
+
+// This code goes here rather than nsGlobalWindow.cpp because nsGlobalWindow.cpp
+// can't include ContentChild.h since it includes windows.h.
+
+static uint64_t gNextWindowID = 0;
+
+// We use only 53 bits for the window ID so that it can be converted to and from
+// a JS value without loss of precision. The upper bits of the window ID hold the
+// process ID. The lower bits identify the window.
+static const uint64_t kWindowIDTotalBits = 53;
+static const uint64_t kWindowIDProcessBits = 22;
+static const uint64_t kWindowIDWindowBits = kWindowIDTotalBits - kWindowIDProcessBits;
+
+// Try to return a window ID that is unique across processes and that will never
+// be recycled.
+uint64_t
+NextWindowID()
+{
+ uint64_t processID = 0;
+ if (XRE_IsContentProcess()) {
+ ContentChild* cc = ContentChild::GetSingleton();
+ processID = cc->GetID();
+ }
+
+ MOZ_RELEASE_ASSERT(processID < (uint64_t(1) << kWindowIDProcessBits));
+ uint64_t processBits = processID & ((uint64_t(1) << kWindowIDProcessBits) - 1);
+
+ // Make sure no actual window ends up with mWindowID == 0.
+ uint64_t windowID = ++gNextWindowID;
+
+ MOZ_RELEASE_ASSERT(windowID < (uint64_t(1) << kWindowIDWindowBits));
+ uint64_t windowBits = windowID & ((uint64_t(1) << kWindowIDWindowBits) - 1);
+
+ return (processBits << kWindowIDWindowBits) | windowBits;
+}
+
+bool
+ContentChild::RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
+ const uint32_t& aAction)
+{
+ nsCOMPtr<nsIDragService> dragService =
+ do_GetService("@mozilla.org/widget/dragservice;1");
+ if (dragService) {
+ dragService->StartDragSession();
+ nsCOMPtr<nsIDragSession> session;
+ dragService->GetCurrentSession(getter_AddRefs(session));
+ if (session) {
+ session->SetDragAction(aAction);
+ // Check if we are receiving any file objects. If we are we will want
+ // to hide any of the other objects coming in from content.
+ bool hasFiles = false;
+ for (uint32_t i = 0; i < aTransfers.Length() && !hasFiles; ++i) {
+ auto& items = aTransfers[i].items();
+ for (uint32_t j = 0; j < items.Length() && !hasFiles; ++j) {
+ if (items[j].data().type() == IPCDataTransferData::TPBlobChild) {
+ hasFiles = true;
+ }
+ }
+ }
+
+ // Add the entries from the IPC to the new DataTransfer
+ nsCOMPtr<DataTransfer> dataTransfer =
+ new DataTransfer(nullptr, eDragStart, false, -1);
+ for (uint32_t i = 0; i < aTransfers.Length(); ++i) {
+ auto& items = aTransfers[i].items();
+ for (uint32_t j = 0; j < items.Length(); ++j) {
+ const IPCDataTransferItem& item = items[j];
+ RefPtr<nsVariantCC> variant = new nsVariantCC();
+ if (item.data().type() == IPCDataTransferData::TnsString) {
+ const nsString& data = item.data().get_nsString();
+ variant->SetAsAString(data);
+ } else if (item.data().type() == IPCDataTransferData::TShmem) {
+ Shmem data = item.data().get_Shmem();
+ variant->SetAsACString(nsDependentCString(data.get<char>(), data.Size<char>()));
+ Unused << DeallocShmem(data);
+ } else if (item.data().type() == IPCDataTransferData::TPBlobChild) {
+ BlobChild* blob = static_cast<BlobChild*>(item.data().get_PBlobChild());
+ RefPtr<BlobImpl> blobImpl = blob->GetBlobImpl();
+ variant->SetAsISupports(blobImpl);
+ } else {
+ continue;
+ }
+ // We should hide this data from content if we have a file, and we aren't a file.
+ bool hidden = hasFiles && item.data().type() != IPCDataTransferData::TPBlobChild;
+ dataTransfer->SetDataWithPrincipalFromOtherProcess(
+ NS_ConvertUTF8toUTF16(item.flavor()), variant, i,
+ nsContentUtils::GetSystemPrincipal(), hidden);
+ }
+ }
+ session->SetDataTransfer(dataTransfer);
+ }
+ }
+ return true;
+}
+
+bool
+ContentChild::RecvEndDragSession(const bool& aDoneDrag,
+ const bool& aUserCancelled,
+ const LayoutDeviceIntPoint& aDragEndPoint)
+{
+ nsCOMPtr<nsIDragService> dragService =
+ do_GetService("@mozilla.org/widget/dragservice;1");
+ if (dragService) {
+ if (aUserCancelled) {
+ nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
+ if (dragSession) {
+ dragSession->UserCancelled();
+ }
+ }
+ static_cast<nsBaseDragService*>(dragService.get())->SetDragEndPoint(aDragEndPoint);
+ dragService->EndDragSession(aDoneDrag);
+ }
+ return true;
+}
+
+bool
+ContentChild::RecvPush(const nsCString& aScope,
+ const IPC::Principal& aPrincipal,
+ const nsString& aMessageId)
+{
+ PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId, Nothing());
+ Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
+ return true;
+}
+
+bool
+ContentChild::RecvPushWithData(const nsCString& aScope,
+ const IPC::Principal& aPrincipal,
+ const nsString& aMessageId,
+ InfallibleTArray<uint8_t>&& aData)
+{
+ PushMessageDispatcher dispatcher(aScope, aPrincipal, aMessageId, Some(aData));
+ Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
+ return true;
+}
+
+bool
+ContentChild::RecvPushSubscriptionChange(const nsCString& aScope,
+ const IPC::Principal& aPrincipal)
+{
+ PushSubscriptionChangeDispatcher dispatcher(aScope, aPrincipal);
+ Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
+ return true;
+}
+
+bool
+ContentChild::RecvPushError(const nsCString& aScope, const IPC::Principal& aPrincipal,
+ const nsString& aMessage, const uint32_t& aFlags)
+{
+ PushErrorDispatcher dispatcher(aScope, aPrincipal, aMessage, aFlags);
+ Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObserversAndWorkers()));
+ return true;
+}
+
+bool
+ContentChild::RecvNotifyPushSubscriptionModifiedObservers(const nsCString& aScope,
+ const IPC::Principal& aPrincipal)
+{
+ PushSubscriptionModifiedDispatcher dispatcher(aScope, aPrincipal);
+ Unused << NS_WARN_IF(NS_FAILED(dispatcher.NotifyObservers()));
+ return true;
+}
+
+bool
+ContentChild::RecvBlobURLRegistration(const nsCString& aURI, PBlobChild* aBlobChild,
+ const IPC::Principal& aPrincipal)
+{
+ RefPtr<BlobImpl> blobImpl = static_cast<BlobChild*>(aBlobChild)->GetBlobImpl();
+ MOZ_ASSERT(blobImpl);
+
+ nsHostObjectProtocolHandler::AddDataEntry(aURI, aPrincipal, blobImpl);
+ return true;
+}
+
+bool
+ContentChild::RecvBlobURLUnregistration(const nsCString& aURI)
+{
+ nsHostObjectProtocolHandler::RemoveDataEntry(aURI);
+ return true;
+}
+
+#if defined(XP_WIN) && defined(ACCESSIBILITY)
+bool
+ContentChild::SendGetA11yContentId()
+{
+ return PContentChild::SendGetA11yContentId(&mMsaaID);
+}
+#endif // defined(XP_WIN) && defined(ACCESSIBILITY)
+
+void
+ContentChild::CreateGetFilesRequest(const nsAString& aDirectoryPath,
+ bool aRecursiveFlag,
+ nsID& aUUID,
+ GetFilesHelperChild* aChild)
+{
+ MOZ_ASSERT(aChild);
+ MOZ_ASSERT(!mGetFilesPendingRequests.GetWeak(aUUID));
+
+ Unused << SendGetFilesRequest(aUUID, nsString(aDirectoryPath),
+ aRecursiveFlag);
+ mGetFilesPendingRequests.Put(aUUID, aChild);
+}
+
+void
+ContentChild::DeleteGetFilesRequest(nsID& aUUID, GetFilesHelperChild* aChild)
+{
+ MOZ_ASSERT(aChild);
+ MOZ_ASSERT(mGetFilesPendingRequests.GetWeak(aUUID));
+
+ Unused << SendDeleteGetFilesRequest(aUUID);
+ mGetFilesPendingRequests.Remove(aUUID);
+}
+
+bool
+ContentChild::RecvGetFilesResponse(const nsID& aUUID,
+ const GetFilesResponseResult& aResult)
+{
+ GetFilesHelperChild* child = mGetFilesPendingRequests.GetWeak(aUUID);
+ // This object can already been deleted in case DeleteGetFilesRequest has
+ // been called when the response was sending by the parent.
+ if (!child) {
+ return true;
+ }
+
+ if (aResult.type() == GetFilesResponseResult::TGetFilesResponseFailure) {
+ child->Finished(aResult.get_GetFilesResponseFailure().errorCode());
+ } else {
+ MOZ_ASSERT(aResult.type() == GetFilesResponseResult::TGetFilesResponseSuccess);
+
+ const nsTArray<PBlobChild*>& blobs =
+ aResult.get_GetFilesResponseSuccess().blobsChild();
+
+ bool succeeded = true;
+ for (uint32_t i = 0; succeeded && i < blobs.Length(); ++i) {
+ RefPtr<BlobImpl> impl = static_cast<BlobChild*>(blobs[i])->GetBlobImpl();
+ succeeded = child->AppendBlobImpl(impl);
+ }
+
+ child->Finished(succeeded ? NS_OK : NS_ERROR_OUT_OF_MEMORY);
+ }
+
+ mGetFilesPendingRequests.Remove(aUUID);
+ return true;
+}
+
+/* static */ void
+ContentChild::FatalErrorIfNotUsingGPUProcess(const char* const aProtocolName,
+ const char* const aErrorMsg,
+ base::ProcessId aOtherPid)
+{
+ // If we're communicating with the same process or the UI process then we
+ // want to crash normally. Otherwise we want to just warn as the other end
+ // must be the GPU process and it crashing shouldn't be fatal for us.
+ if (aOtherPid == base::GetCurrentProcId() ||
+ (GetSingleton() && GetSingleton()->OtherPid() == aOtherPid)) {
+ mozilla::ipc::FatalError(aProtocolName, aErrorMsg, false);
+ } else {
+ nsAutoCString formattedMessage("IPDL error [");
+ formattedMessage.AppendASCII(aProtocolName);
+ formattedMessage.AppendLiteral("]: \"");
+ formattedMessage.AppendASCII(aErrorMsg);
+ formattedMessage.AppendLiteral("\".");
+ NS_WARNING(formattedMessage.get());
+ }
+}
+
+} // namespace dom
+} // namespace mozilla