mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 14:55:47 +00:00
5d61a2312b
Differential Revision: https://phabricator.services.mozilla.com/D137475
269 lines
8.3 KiB
C++
269 lines
8.3 KiB
C++
/* -*- 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/ipc/GeckoChildProcessHost.h"
|
|
#include "mozilla/UniquePtrExtensions.h"
|
|
#include "nsPrintfCString.h"
|
|
|
|
#include "XPCSelfHostedShmem.h"
|
|
|
|
namespace mozilla {
|
|
namespace ipc {
|
|
|
|
SharedPreferenceSerializer::SharedPreferenceSerializer(
|
|
std::function<bool(const char*)>&& aShouldSerializeFn)
|
|
: mPrefMapSize(0), mPrefsLength(0), mShouldSerializeFn(aShouldSerializeFn) {
|
|
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() {
|
|
mPrefMapHandle =
|
|
Preferences::EnsureSnapshot(&mPrefMapSize).TakePlatformHandle();
|
|
|
|
// Serialize the early prefs.
|
|
nsAutoCStringN<1024> prefs;
|
|
Preferences::SerializePreferences(prefs, mShouldSerializeFn);
|
|
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
|