Files
tubestation/ipc/glue/ProcessUtils_common.cpp
Nika Layzell 62686c41b3 Bug 1440207 - Part 3a: Migrate GeckoChildProcessHost callers to use ChildProcessArgs, r=ipc-reviewers,necko-reviewers,media-playback-reviewers,aosmond,mccr8
This patch implements the majority of the public interface for the new IPC
handle passing design.

The rough design is an expansion of `geckoargs` to allow passing
`UniqueFileHandle` arguments to child processes. This replaces the existing
extra options array to make the list of files explicit.

This currently just replaces things which were already passed this way on the
command line from outside of GeckoChildProcessHost. Note that this does not
migrate callers which were not already passing file handles using geckoargs,
and does not implement the actual OS-level support for passing arguments this
way.

Differential Revision: https://phabricator.services.mozilla.com/D221371
2024-09-24 19:28:09 +00:00

181 lines
5.9 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/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,
geckoargs::ChildProcessArgs& aExtraOpts) const {
UniqueFileHandle prefsHandle = DuplicateFileHandle(GetPrefsHandle());
MOZ_RELEASE_ASSERT(prefsHandle, "failed to duplicate prefs handle");
UniqueFileHandle prefMapHandle = DuplicateFileHandle(GetPrefMapHandle());
MOZ_RELEASE_ASSERT(prefMapHandle, "failed to duplicate pref map handle");
// Pass the handles and lengths via command line flags.
geckoargs::sPrefsHandle.Put(std::move(prefsHandle), aExtraOpts);
geckoargs::sPrefsLen.Put((uintptr_t)(GetPrefsLength()), aExtraOpts);
geckoargs::sPrefMapHandle.Put(std::move(prefMapHandle), aExtraOpts);
geckoargs::sPrefMapSize.Put((uintptr_t)(GetPrefMapSize()), aExtraOpts);
}
SharedPreferenceDeserializer::SharedPreferenceDeserializer() {
MOZ_COUNT_CTOR(SharedPreferenceDeserializer);
}
SharedPreferenceDeserializer::~SharedPreferenceDeserializer() {
MOZ_COUNT_DTOR(SharedPreferenceDeserializer);
}
bool SharedPreferenceDeserializer::DeserializeFromSharedMemory(
UniqueFileHandle aPrefsHandle, UniqueFileHandle aPrefMapHandle,
uint64_t aPrefsLen, uint64_t aPrefMapSize) {
if (!aPrefsHandle || !aPrefMapHandle || !aPrefsLen || !aPrefMapSize) {
return false;
}
mPrefMapHandle.emplace(std::move(aPrefMapHandle));
mPrefsLen = Some((uintptr_t)(aPrefsLen));
mPrefMapSize = Some((uintptr_t)(aPrefMapSize));
// 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(aPrefsHandle), /* 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();
}
void ExportSharedJSInit(mozilla::ipc::GeckoChildProcessHost& procHost,
geckoargs::ChildProcessArgs& aExtraOpts) {
#if defined(ANDROID) || defined(XP_IOS)
// The code to support Android/iOS is added in a follow-up patch.
return;
#else
auto& shmem = xpc::SelfHostedShmem::GetSingleton();
UniqueFileHandle handle = DuplicateFileHandle(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 (!handle || !len) {
return;
}
// command line: -jsInitHandle handle -jsInitLen length
geckoargs::sJsInitHandle.Put(std::move(handle), aExtraOpts);
geckoargs::sJsInitLen.Put((uintptr_t)(len), aExtraOpts);
#endif
}
bool ImportSharedJSInit(UniqueFileHandle 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 || !aJsInitHandle) {
return true;
}
size_t len = (uintptr_t)(aJsInitLen);
if (!len) {
return false;
}
// 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(aJsInitHandle), len)) {
NS_ERROR("failed to open shared memory in the child");
return false;
}
return true;
}
} // namespace ipc
} // namespace mozilla