summaryrefslogtreecommitdiffstats
path: root/ipc/glue/ProcessUtils_common.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--ipc/glue/ProcessUtils_common.cpp275
1 files changed, 275 insertions, 0 deletions
diff --git a/ipc/glue/ProcessUtils_common.cpp b/ipc/glue/ProcessUtils_common.cpp
new file mode 100644
index 0000000000..69eb4bdf28
--- /dev/null
+++ b/ipc/glue/ProcessUtils_common.cpp
@@ -0,0 +1,275 @@
+/* -*- 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/. */
+
+#include "ProcessUtils.h"
+
+#include "mozilla/Preferences.h"
+#include "mozilla/GeckoArgs.h"
+#include "mozilla/dom/RemoteType.h"
+#include "mozilla/ipc/GeckoChildProcessHost.h"
+#include "mozilla/UniquePtrExtensions.h"
+#include "nsPrintfCString.h"
+
+#include "XPCSelfHostedShmem.h"
+
+namespace mozilla {
+namespace ipc {
+
+SharedPreferenceSerializer::SharedPreferenceSerializer()
+ : mPrefMapSize(0), mPrefsLength(0) {
+ MOZ_COUNT_CTOR(SharedPreferenceSerializer);
+}
+
+SharedPreferenceSerializer::~SharedPreferenceSerializer() {
+ MOZ_COUNT_DTOR(SharedPreferenceSerializer);
+}
+
+SharedPreferenceSerializer::SharedPreferenceSerializer(
+ SharedPreferenceSerializer&& aOther)
+ : mPrefMapSize(aOther.mPrefMapSize),
+ mPrefsLength(aOther.mPrefsLength),
+ mPrefMapHandle(std::move(aOther.mPrefMapHandle)),
+ mPrefsHandle(std::move(aOther.mPrefsHandle)) {
+ MOZ_COUNT_CTOR(SharedPreferenceSerializer);
+}
+
+bool SharedPreferenceSerializer::SerializeToSharedMemory(
+ const GeckoProcessType aDestinationProcessType,
+ const nsACString& aDestinationRemoteType) {
+ mPrefMapHandle =
+ Preferences::EnsureSnapshot(&mPrefMapSize).TakePlatformHandle();
+
+ bool destIsWebContent =
+ aDestinationProcessType == GeckoProcessType_Content &&
+ (StringBeginsWith(aDestinationRemoteType, WEB_REMOTE_TYPE) ||
+ StringBeginsWith(aDestinationRemoteType, PREALLOC_REMOTE_TYPE));
+
+ // Serialize the early prefs.
+ nsAutoCStringN<1024> prefs;
+ Preferences::SerializePreferences(prefs, destIsWebContent);
+ mPrefsLength = prefs.Length();
+
+ base::SharedMemory shm;
+ // Set up the shared memory.
+ if (!shm.Create(prefs.Length())) {
+ NS_ERROR("failed to create shared memory in the parent");
+ return false;
+ }
+ if (!shm.Map(prefs.Length())) {
+ NS_ERROR("failed to map shared memory in the parent");
+ return false;
+ }
+
+ // Copy the serialized prefs into the shared memory.
+ memcpy(static_cast<char*>(shm.memory()), prefs.get(), mPrefsLength);
+
+ mPrefsHandle = shm.TakeHandle();
+ return true;
+}
+
+void SharedPreferenceSerializer::AddSharedPrefCmdLineArgs(
+ mozilla::ipc::GeckoChildProcessHost& procHost,
+ std::vector<std::string>& aExtraOpts) const {
+#if defined(XP_WIN)
+ // Record the handle as to-be-shared, and pass it via a command flag. This
+ // works because Windows handles are system-wide.
+ procHost.AddHandleToShare(GetPrefsHandle().get());
+ procHost.AddHandleToShare(GetPrefMapHandle().get());
+ geckoargs::sPrefsHandle.Put((uintptr_t)(GetPrefsHandle().get()), aExtraOpts);
+ geckoargs::sPrefMapHandle.Put((uintptr_t)(GetPrefMapHandle().get()),
+ aExtraOpts);
+#else
+ // In contrast, Unix fds are per-process. So remap the fd to a fixed one that
+ // will be used in the child.
+ // XXX: bug 1440207 is about improving how fixed fds are used.
+ //
+ // Note: on Android, AddFdToRemap() sets up the fd to be passed via a Parcel,
+ // and the fixed fd isn't used. However, we still need to mark it for
+ // remapping so it doesn't get closed in the child.
+ procHost.AddFdToRemap(GetPrefsHandle().get(), kPrefsFileDescriptor);
+ procHost.AddFdToRemap(GetPrefMapHandle().get(), kPrefMapFileDescriptor);
+#endif
+
+ // Pass the lengths via command line flags.
+ geckoargs::sPrefsLen.Put((uintptr_t)(GetPrefsLength()), aExtraOpts);
+ geckoargs::sPrefMapSize.Put((uintptr_t)(GetPrefMapSize()), aExtraOpts);
+}
+
+#ifdef ANDROID
+static int gPrefsFd = -1;
+static int gPrefMapFd = -1;
+
+void SetPrefsFd(int aFd) { gPrefsFd = aFd; }
+
+void SetPrefMapFd(int aFd) { gPrefMapFd = aFd; }
+#endif
+
+SharedPreferenceDeserializer::SharedPreferenceDeserializer() {
+ MOZ_COUNT_CTOR(SharedPreferenceDeserializer);
+}
+
+SharedPreferenceDeserializer::~SharedPreferenceDeserializer() {
+ MOZ_COUNT_DTOR(SharedPreferenceDeserializer);
+}
+
+bool SharedPreferenceDeserializer::DeserializeFromSharedMemory(
+ uint64_t aPrefsHandle, uint64_t aPrefMapHandle, uint64_t aPrefsLen,
+ uint64_t aPrefMapSize) {
+ Maybe<base::SharedMemoryHandle> prefsHandle;
+
+#ifdef XP_WIN
+ prefsHandle = Some(UniqueFileHandle(HANDLE((uintptr_t)(aPrefsHandle))));
+ if (!aPrefsHandle) {
+ return false;
+ }
+
+ FileDescriptor::UniquePlatformHandle handle(
+ HANDLE((uintptr_t)(aPrefMapHandle)));
+ if (!aPrefMapHandle) {
+ return false;
+ }
+
+ mPrefMapHandle.emplace(std::move(handle));
+#endif
+
+ mPrefsLen = Some((uintptr_t)(aPrefsLen));
+ if (!aPrefsLen) {
+ return false;
+ }
+
+ mPrefMapSize = Some((uintptr_t)(aPrefMapSize));
+ if (!aPrefMapSize) {
+ return false;
+ }
+
+#ifdef ANDROID
+ // Android is different; get the FD via gPrefsFd instead of a fixed fd.
+ MOZ_RELEASE_ASSERT(gPrefsFd != -1);
+ prefsHandle = Some(UniqueFileHandle(gPrefsFd));
+
+ mPrefMapHandle.emplace(UniqueFileHandle(gPrefMapFd));
+#elif XP_UNIX
+ prefsHandle = Some(UniqueFileHandle(kPrefsFileDescriptor));
+
+ mPrefMapHandle.emplace(UniqueFileHandle(kPrefMapFileDescriptor));
+#endif
+
+ if (prefsHandle.isNothing() || mPrefsLen.isNothing() ||
+ mPrefMapHandle.isNothing() || mPrefMapSize.isNothing()) {
+ return false;
+ }
+
+ // Init the shared-memory base preference mapping first, so that only changed
+ // preferences wind up in heap memory.
+ Preferences::InitSnapshot(mPrefMapHandle.ref(), *mPrefMapSize);
+
+ // Set up early prefs from the shared memory.
+ if (!mShmem.SetHandle(std::move(*prefsHandle), /* read_only */ true)) {
+ NS_ERROR("failed to open shared memory in the child");
+ return false;
+ }
+ if (!mShmem.Map(*mPrefsLen)) {
+ NS_ERROR("failed to map shared memory in the child");
+ return false;
+ }
+ Preferences::DeserializePreferences(static_cast<char*>(mShmem.memory()),
+ *mPrefsLen);
+
+ return true;
+}
+
+const FileDescriptor& SharedPreferenceDeserializer::GetPrefMapHandle() const {
+ MOZ_ASSERT(mPrefMapHandle.isSome());
+
+ return mPrefMapHandle.ref();
+}
+
+#ifdef XP_UNIX
+// On Unix, file descriptors are per-process. This value is used when mapping
+// a parent process handle to a content process handle.
+static const int kJSInitFileDescriptor = 11;
+#endif
+
+void ExportSharedJSInit(mozilla::ipc::GeckoChildProcessHost& procHost,
+ std::vector<std::string>& aExtraOpts) {
+#ifdef ANDROID
+ // The code to support Android is added in a follow-up patch.
+ return;
+#else
+ auto& shmem = xpc::SelfHostedShmem::GetSingleton();
+ const mozilla::UniqueFileHandle& uniqHandle = shmem.Handle();
+ size_t len = shmem.Content().Length();
+
+ // If the file is not found or the content is empty, then we would start the
+ // content process without this optimization.
+ if (!uniqHandle || !len) {
+ return;
+ }
+
+ mozilla::detail::FileHandleType handle = uniqHandle.get();
+ // command line: [-jsInitHandle handle] -jsInitLen length
+# if defined(XP_WIN)
+ // Record the handle as to-be-shared, and pass it via a command flag.
+ procHost.AddHandleToShare(HANDLE(handle));
+ geckoargs::sJsInitHandle.Put((uintptr_t)(HANDLE(handle)), aExtraOpts);
+# else
+ // In contrast, Unix fds are per-process. So remap the fd to a fixed one that
+ // will be used in the child.
+ // XXX: bug 1440207 is about improving how fixed fds are used.
+ //
+ // Note: on Android, AddFdToRemap() sets up the fd to be passed via a Parcel,
+ // and the fixed fd isn't used. However, we still need to mark it for
+ // remapping so it doesn't get closed in the child.
+ procHost.AddFdToRemap(handle, kJSInitFileDescriptor);
+# endif
+
+ // Pass the lengths via command line flags.
+ geckoargs::sJsInitLen.Put((uintptr_t)(len), aExtraOpts);
+#endif
+}
+
+bool ImportSharedJSInit(uint64_t aJsInitHandle, uint64_t aJsInitLen) {
+ // This is an optimization, and as such we can safely recover if the command
+ // line argument are not provided.
+ if (!aJsInitLen) {
+ return true;
+ }
+
+#ifdef XP_WIN
+ if (!aJsInitHandle) {
+ return true;
+ }
+#endif
+
+#ifdef XP_WIN
+ base::SharedMemoryHandle handle(HANDLE((uintptr_t)(aJsInitHandle)));
+ if (!aJsInitHandle) {
+ return false;
+ }
+#endif
+
+ size_t len = (uintptr_t)(aJsInitLen);
+ if (!aJsInitLen) {
+ return false;
+ }
+
+#ifdef XP_UNIX
+ auto handle = UniqueFileHandle(kJSInitFileDescriptor);
+#endif
+
+ // Initialize the shared memory with the file handle and size of the content
+ // of the self-hosted Xdr.
+ auto& shmem = xpc::SelfHostedShmem::GetSingleton();
+ if (!shmem.InitFromChild(std::move(handle), len)) {
+ NS_ERROR("failed to open shared memory in the child");
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace ipc
+} // namespace mozilla