mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 16:55:40 +00:00
9a41450b28
Despite the comment saying not to use the "handle" except as an opaque identifier, it is being used to pass the handle to other OS APIs. Direct access to the handle needs to be controlled to make sure freezing is safe, so this patch replaces that with interfaces that are more explicit about ownership and lifetime. Depends on D26739 Differential Revision: https://phabricator.services.mozilla.com/D26740 --HG-- extra : moz-landing-system : lando
211 lines
6.7 KiB
C++
211 lines
6.7 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/ipc/GeckoChildProcessHost.h"
|
|
#include "mozilla/UniquePtrExtensions.h"
|
|
|
|
namespace mozilla {
|
|
namespace ipc {
|
|
|
|
SharedPreferenceSerializer::SharedPreferenceSerializer() : mPrefMapSize(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() {
|
|
mPrefMapHandle =
|
|
Preferences::EnsureSnapshot(&mPrefMapSize).TakePlatformHandle();
|
|
|
|
// Serialize the early prefs.
|
|
nsAutoCStringN<1024> prefs;
|
|
Preferences::SerializePreferences(prefs);
|
|
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 {
|
|
// Formats a pointer or pointer-sized-integer as a string suitable for passing
|
|
// in an arguments list.
|
|
auto formatPtrArg = [](auto arg) {
|
|
return nsPrintfCString("%zu", uintptr_t(arg));
|
|
};
|
|
|
|
#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());
|
|
aExtraOpts.push_back("-prefsHandle");
|
|
aExtraOpts.push_back(formatPtrArg(GetPrefsHandle().get()).get());
|
|
aExtraOpts.push_back("-prefMapHandle");
|
|
aExtraOpts.push_back(formatPtrArg(GetPrefMapHandle().get()).get());
|
|
#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.
|
|
aExtraOpts.push_back("-prefsLen");
|
|
aExtraOpts.push_back(formatPtrArg(GetPrefsLength()).get());
|
|
aExtraOpts.push_back("-prefMapSize");
|
|
aExtraOpts.push_back(formatPtrArg(GetPrefMapSize()).get());
|
|
}
|
|
|
|
#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(
|
|
char* aPrefsHandleStr, char* aPrefMapHandleStr, char* aPrefsLenStr,
|
|
char* aPrefMapSizeStr) {
|
|
#ifdef XP_WIN
|
|
MOZ_ASSERT(aPrefsHandleStr && aPrefMapHandleStr, "Can't be null");
|
|
#endif
|
|
MOZ_ASSERT(aPrefsLenStr && aPrefMapSizeStr, "Can't be null");
|
|
|
|
// Parses an arg containing a pointer-sized-integer.
|
|
auto parseUIntPtrArg = [](char*& aArg) {
|
|
// ContentParent uses %zu to print a word-sized unsigned integer. So
|
|
// even though strtoull() returns a long long int, it will fit in a
|
|
// uintptr_t.
|
|
return uintptr_t(strtoull(aArg, &aArg, 10));
|
|
};
|
|
|
|
#ifdef XP_WIN
|
|
auto parseHandleArg = [&](char*& aArg) {
|
|
return HANDLE(parseUIntPtrArg(aArg));
|
|
};
|
|
|
|
mPrefsHandle = Some(parseHandleArg(aPrefsHandleStr));
|
|
if (!aPrefsHandleStr || aPrefsHandleStr[0] != '\0') {
|
|
return false;
|
|
}
|
|
|
|
FileDescriptor::UniquePlatformHandle handle(
|
|
parseHandleArg(aPrefMapHandleStr));
|
|
if (!aPrefMapHandleStr || aPrefMapHandleStr[0] != '\0') {
|
|
return false;
|
|
}
|
|
|
|
mPrefMapHandle.emplace(std::move(handle));
|
|
#endif
|
|
|
|
mPrefsLen = Some(parseUIntPtrArg(aPrefsLenStr));
|
|
if (!aPrefsLenStr || aPrefsLenStr[0] != '\0') {
|
|
return false;
|
|
}
|
|
|
|
mPrefMapSize = Some(parseUIntPtrArg(aPrefMapSizeStr));
|
|
if (!aPrefMapSizeStr || aPrefMapSizeStr[0] != '\0') {
|
|
return false;
|
|
}
|
|
|
|
#ifdef ANDROID
|
|
// Android is different; get the FD via gPrefsFd instead of a fixed fd.
|
|
MOZ_RELEASE_ASSERT(gPrefsFd != -1);
|
|
mPrefsHandle = Some(base::FileDescriptor(gPrefsFd, /* auto_close */ true));
|
|
|
|
mPrefMapHandle.emplace(UniqueFileHandle(gPrefMapFd));
|
|
#elif XP_UNIX
|
|
mPrefsHandle = Some(base::FileDescriptor(kPrefsFileDescriptor,
|
|
/* auto_close */ true));
|
|
|
|
mPrefMapHandle.emplace(UniqueFileHandle(kPrefMapFileDescriptor));
|
|
#endif
|
|
|
|
if (mPrefsHandle.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(*mPrefsHandle, /* 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 base::SharedMemoryHandle& SharedPreferenceDeserializer::GetPrefsHandle()
|
|
const {
|
|
MOZ_ASSERT(mPrefsHandle.isSome());
|
|
|
|
return mPrefsHandle.ref();
|
|
}
|
|
|
|
const FileDescriptor& SharedPreferenceDeserializer::GetPrefMapHandle() const {
|
|
MOZ_ASSERT(mPrefMapHandle.isSome());
|
|
|
|
return mPrefMapHandle.ref();
|
|
}
|
|
|
|
} // namespace ipc
|
|
} // namespace mozilla
|