Improve management of command-line passed shared memory handle.
This CL changes the shared memory handle switch logic to allow the browser process to retain its handle in order to properly dispose of it when the child process assumes ownership and/or terminates. On Windows, in particular, we are seeing evidence that these handles are being leaked and/or perhaps being inadvertently being mapped twice. Ownership of the handles is shared between the child process host and the child process launcher/helper, which operate asynchronously to one another. As such, the handles are managed as refcounted data. Note: The handles are not accessed asynchronously. Either the launcher (via command line) or the host (via IPC) passes the handle to the child, but their destruction order is non-deterministic. Bug: 351671612, 40109064, 40818143 Change-Id: Ie4d17ad7ce0d29218f926f137dda61d94983d22a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6098050 Reviewed-by: Arthur Sonzogni <arthursonzogni@chromium.org> Commit-Queue: Roger McFarlane <rogerm@chromium.org> Reviewed-by: Etienne Pierre-Doray <etiennep@chromium.org> Reviewed-by: Alexei Svitkine <asvitkine@chromium.org> Cr-Commit-Position: refs/heads/main@{#1408794}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
691822a2db
commit
f9fc4f9fc7
base
memory
metrics
components/metrics
content/browser
browser_child_process_host_impl.ccbrowser_child_process_host_impl.hchild_process_launcher.ccchild_process_launcher.hchild_process_launcher_helper.ccchild_process_launcher_helper.h
metrics
renderer_host
services/tracing/public/cpp
@ -9,6 +9,7 @@
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/platform_shared_memory_handle.h"
|
||||
#include "base/memory/read_only_shared_memory_region.h"
|
||||
#include "base/memory/unsafe_shared_memory_region.h"
|
||||
#include "base/process/launch.h"
|
||||
@ -60,42 +61,47 @@
|
||||
// 3. The high 64 bits of the shared memory block GUID.
|
||||
// 4. The low 64 bits of the shared memory block GUID.
|
||||
// 5. The size of the shared memory segment as a string.
|
||||
//
|
||||
// TODO(crbug.com/389713696): Refactor the platform specific parts of this file.
|
||||
|
||||
namespace base::shared_memory {
|
||||
namespace {
|
||||
|
||||
using subtle::PlatformSharedMemoryRegion;
|
||||
using subtle::ScopedPlatformSharedMemoryHandle;
|
||||
using base::subtle::PlatformSharedMemoryRegion;
|
||||
using base::subtle::ScopedPlatformSharedMemoryHandle;
|
||||
|
||||
// The max shared memory size is artificially limited. This serves as a sanity
|
||||
// check when serializing/deserializing the handle info. This value should be
|
||||
// slightly larger than the largest shared memory size used in practice.
|
||||
constexpr size_t kMaxSharedMemorySize = 8 << 20; // 8 MiB
|
||||
|
||||
#if BUILDFLAG(IS_FUCHSIA)
|
||||
// Return a scoped platform shared memory handle for |shmem_region|, possibly
|
||||
// with permissions reduced to make the handle read-only.
|
||||
ScopedPlatformSharedMemoryHandle GetPlatformHandle(
|
||||
PlatformSharedMemoryRegion& shmem_region,
|
||||
[[maybe_unused]] bool make_read_only) {
|
||||
#if BUILDFLAG(IS_FUCHSIA)
|
||||
if (make_read_only) {
|
||||
// For Fuchsia, ScopedPlatformSharedMemoryHandle <==> zx::vmo
|
||||
zx::vmo scoped_handle;
|
||||
zx_status_t status = shmem_region.GetPlatformHandle()->duplicate(
|
||||
ZX_RIGHT_READ | ZX_RIGHT_MAP | ZX_RIGHT_TRANSFER |
|
||||
ZX_RIGHT_GET_PROPERTY | ZX_RIGHT_DUPLICATE,
|
||||
&scoped_handle);
|
||||
ZX_CHECK(status == ZX_OK, status) << "zx_handle_duplicate";
|
||||
return scoped_handle;
|
||||
// For Fuchsia:
|
||||
// * ScopedPlatformSharedMemoryHandle <==> zx::vmo
|
||||
zx::vmo GetFuchsiaHandle(ScopedPlatformSharedMemoryHandle shmem_handle,
|
||||
bool make_read_only) {
|
||||
if (!make_read_only) {
|
||||
return shmem_handle;
|
||||
}
|
||||
#endif // BUILDFLAG(IS_FUCHSIA)
|
||||
return shmem_region.PassPlatformHandle();
|
||||
zx::vmo scoped_handle;
|
||||
zx_status_t status =
|
||||
shmem_handle.duplicate(ZX_RIGHT_READ | ZX_RIGHT_MAP | ZX_RIGHT_TRANSFER |
|
||||
ZX_RIGHT_GET_PROPERTY | ZX_RIGHT_DUPLICATE,
|
||||
&scoped_handle);
|
||||
ZX_CHECK(status == ZX_OK, status) << "zx_handle_duplicate";
|
||||
return scoped_handle;
|
||||
}
|
||||
#endif // BUILDFLAG(IS_FUCHSIA)
|
||||
|
||||
// Serializes the shared memory region metadata to a string that can be added
|
||||
// to the command-line of a child-process.
|
||||
std::string Serialize(PlatformSharedMemoryRegion shmem_region,
|
||||
bool is_read_only,
|
||||
template <typename HandleType>
|
||||
std::string Serialize(HandleType shmem_handle,
|
||||
const UnguessableToken& shmem_token,
|
||||
size_t shmem_size,
|
||||
[[maybe_unused]] bool is_read_only,
|
||||
#if BUILDFLAG(IS_APPLE)
|
||||
MachPortsForRendezvous::key_type rendezvous_key,
|
||||
#elif BUILDFLAG(IS_POSIX)
|
||||
@ -107,12 +113,6 @@ std::string Serialize(PlatformSharedMemoryRegion shmem_region,
|
||||
CHECK(launch_options != nullptr);
|
||||
#endif
|
||||
|
||||
CHECK(shmem_region.IsValid());
|
||||
|
||||
auto shmem_token = shmem_region.GetGUID();
|
||||
auto shmem_size = shmem_region.GetSize();
|
||||
auto shmem_handle = GetPlatformHandle(shmem_region, is_read_only);
|
||||
|
||||
CHECK(shmem_token);
|
||||
CHECK_NE(shmem_size, 0u);
|
||||
CHECK_LE(shmem_size, kMaxSharedMemorySize);
|
||||
@ -127,15 +127,16 @@ std::string Serialize(PlatformSharedMemoryRegion shmem_region,
|
||||
serialized.reserve(kSerializedReservedSize);
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
// Ownership of the handle is passed to |launch_options|. We keep a non-
|
||||
// owning alias for a moment, so we can serialize the handle's numeric
|
||||
// value.
|
||||
HANDLE handle = shmem_handle.release();
|
||||
launch_options->handles_to_inherit.push_back(handle);
|
||||
// If the child is launched in elevated privilege mode, it will query the
|
||||
// parent for the handle. Otherwise, in non-elevated mode, the handle will
|
||||
// be passed via process inheritance.
|
||||
if (!launch_options->elevated) {
|
||||
launch_options->handles_to_inherit.push_back(shmem_handle);
|
||||
}
|
||||
|
||||
// Tell the child process the name of the HANDLE and whether to handle can
|
||||
// be inherited ('i') or must be duplicate from the parent process ('p').
|
||||
StrAppend(&serialized, {NumberToString(win::HandleToUint32(handle)),
|
||||
StrAppend(&serialized, {NumberToString(win::HandleToUint32(shmem_handle)),
|
||||
(launch_options->elevated ? ",p," : ",i,")});
|
||||
#elif BUILDFLAG(IS_APPLE)
|
||||
// In the receiving child, the handle is looked up using the rendezvous key.
|
||||
@ -146,8 +147,10 @@ std::string Serialize(PlatformSharedMemoryRegion shmem_region,
|
||||
// The handle is passed via the handles to transfer launch options. The child
|
||||
// will use the returned handle_id to lookup the handle. Ownership of the
|
||||
// handle is transferred to |launch_options|.
|
||||
zx::vmo scoped_handle =
|
||||
GetFuchsiaHandle(std::move(shmem_handle), is_read_only);
|
||||
uint32_t handle_id = LaunchOptions::AddHandleToTransfer(
|
||||
&launch_options->handles_to_transfer, shmem_handle.release());
|
||||
&launch_options->handles_to_transfer, scoped_handle.release());
|
||||
StrAppend(&serialized, {NumberToString(handle_id), ",i,"});
|
||||
#elif BUILDFLAG(IS_POSIX)
|
||||
// Serialize the key by which the child can lookup the shared memory handle.
|
||||
@ -304,22 +307,32 @@ expected<PlatformSharedMemoryRegion, SharedMemoryError> Deserialize(
|
||||
std::move(scoped_handle), mode, checked_cast<size_t>(size), guid.value());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void AddToLaunchParameters(std::string_view switch_name,
|
||||
ReadOnlySharedMemoryRegion read_only_memory_region,
|
||||
template <typename RegionType>
|
||||
void AddToLaunchParametersImpl(std::string_view switch_name,
|
||||
const RegionType& memory_region,
|
||||
#if BUILDFLAG(IS_APPLE)
|
||||
MachPortsForRendezvous::key_type rendezvous_key,
|
||||
MachPortsForRendezvous::key_type rendezvous_key,
|
||||
#elif BUILDFLAG(IS_POSIX)
|
||||
GlobalDescriptors::Key descriptor_key,
|
||||
ScopedFD& out_descriptor_to_share,
|
||||
GlobalDescriptors::Key descriptor_key,
|
||||
ScopedFD& out_descriptor_to_share,
|
||||
#endif
|
||||
CommandLine* command_line,
|
||||
LaunchOptions* launch_options) {
|
||||
CommandLine* command_line,
|
||||
LaunchOptions* launch_options) {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
auto token = memory_region.GetGUID();
|
||||
auto size = memory_region.GetSize();
|
||||
auto handle = memory_region.GetPlatformHandle();
|
||||
#else
|
||||
auto region =
|
||||
RegionType::TakeHandleForSerialization(memory_region.Duplicate());
|
||||
auto token = region.GetGUID();
|
||||
auto size = region.GetSize();
|
||||
auto handle = region.PassPlatformHandle();
|
||||
#endif // !BUILDFLAG(IS_WIN)
|
||||
constexpr bool is_read_only =
|
||||
std::is_same<RegionType, ReadOnlySharedMemoryRegion>::value;
|
||||
std::string switch_value =
|
||||
Serialize(ReadOnlySharedMemoryRegion::TakeHandleForSerialization(
|
||||
std::move(read_only_memory_region)),
|
||||
/*is_read_only=*/true,
|
||||
Serialize(std::move(handle), token, size, is_read_only,
|
||||
#if BUILDFLAG(IS_APPLE)
|
||||
rendezvous_key,
|
||||
#elif BUILDFLAG(IS_POSIX)
|
||||
@ -329,8 +342,30 @@ void AddToLaunchParameters(std::string_view switch_name,
|
||||
command_line->AppendSwitchASCII(switch_name, switch_value);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void AddToLaunchParameters(
|
||||
std::string_view switch_name,
|
||||
const ReadOnlySharedMemoryRegion& read_only_memory_region,
|
||||
#if BUILDFLAG(IS_APPLE)
|
||||
MachPortsForRendezvous::key_type rendezvous_key,
|
||||
#elif BUILDFLAG(IS_POSIX)
|
||||
GlobalDescriptors::Key descriptor_key,
|
||||
ScopedFD& out_descriptor_to_share,
|
||||
#endif
|
||||
CommandLine* command_line,
|
||||
LaunchOptions* launch_options) {
|
||||
AddToLaunchParametersImpl(switch_name, read_only_memory_region,
|
||||
#if BUILDFLAG(IS_APPLE)
|
||||
rendezvous_key,
|
||||
#elif BUILDFLAG(IS_POSIX)
|
||||
descriptor_key, out_descriptor_to_share,
|
||||
#endif
|
||||
command_line, launch_options);
|
||||
}
|
||||
|
||||
void AddToLaunchParameters(std::string_view switch_name,
|
||||
UnsafeSharedMemoryRegion unsafe_memory_region,
|
||||
const UnsafeSharedMemoryRegion& unsafe_memory_region,
|
||||
#if BUILDFLAG(IS_APPLE)
|
||||
MachPortsForRendezvous::key_type rendezvous_key,
|
||||
#elif BUILDFLAG(IS_POSIX)
|
||||
@ -339,17 +374,13 @@ void AddToLaunchParameters(std::string_view switch_name,
|
||||
#endif
|
||||
CommandLine* command_line,
|
||||
LaunchOptions* launch_options) {
|
||||
std::string switch_value =
|
||||
Serialize(UnsafeSharedMemoryRegion::TakeHandleForSerialization(
|
||||
std::move(unsafe_memory_region)),
|
||||
/*is_read_only=*/false,
|
||||
AddToLaunchParametersImpl(switch_name, unsafe_memory_region,
|
||||
#if BUILDFLAG(IS_APPLE)
|
||||
rendezvous_key,
|
||||
rendezvous_key,
|
||||
#elif BUILDFLAG(IS_POSIX)
|
||||
descriptor_key, out_descriptor_to_share,
|
||||
descriptor_key, out_descriptor_to_share,
|
||||
#endif
|
||||
launch_options);
|
||||
command_line->AppendSwitchASCII(switch_name, switch_value);
|
||||
command_line, launch_options);
|
||||
}
|
||||
|
||||
expected<UnsafeSharedMemoryRegion, SharedMemoryError>
|
||||
@ -378,7 +409,7 @@ ReadOnlySharedMemoryRegionFrom(std::string_view switch_value) {
|
||||
auto shmem_region = ReadOnlySharedMemoryRegion::Deserialize(
|
||||
std::move(platform_handle).value());
|
||||
if (!shmem_region.IsValid()) {
|
||||
LOG(ERROR) << "Faield to deserialize read-only memory handle";
|
||||
LOG(ERROR) << "Failed to deserialize read-only memory handle";
|
||||
return unexpected(SharedMemoryError::kDeserializeFailed);
|
||||
}
|
||||
return ok(std::move(shmem_region));
|
||||
|
@ -59,7 +59,7 @@ enum class SharedMemoryError {
|
||||
// descriptor to the launch flow for the zygote.
|
||||
BASE_EXPORT void AddToLaunchParameters(
|
||||
std::string_view switch_name,
|
||||
ReadOnlySharedMemoryRegion read_only_memory_region,
|
||||
const ReadOnlySharedMemoryRegion& read_only_memory_region,
|
||||
#if BUILDFLAG(IS_APPLE)
|
||||
MachPortsForRendezvous::key_type rendezvous_key,
|
||||
#elif BUILDFLAG(IS_POSIX)
|
||||
@ -79,7 +79,7 @@ BASE_EXPORT void AddToLaunchParameters(
|
||||
// descriptor to the launch flow for the zygote.
|
||||
BASE_EXPORT void AddToLaunchParameters(
|
||||
std::string_view switch_name,
|
||||
UnsafeSharedMemoryRegion unsafe_memory_region,
|
||||
const UnsafeSharedMemoryRegion& unsafe_memory_region,
|
||||
#if BUILDFLAG(IS_APPLE)
|
||||
MachPortsForRendezvous::key_type rendezvous_key,
|
||||
#elif BUILDFLAG(IS_POSIX)
|
||||
|
@ -119,8 +119,7 @@ TEST_P(SharedMemorySwitchTest, PassViaSwitch) {
|
||||
|
||||
// Update the launch parameters.
|
||||
if (read_only) {
|
||||
AddToLaunchParameters(kSharedMemoryData,
|
||||
read_only_region.region.Duplicate(),
|
||||
AddToLaunchParameters(kSharedMemoryData, read_only_region.region,
|
||||
#if BUILDFLAG(IS_APPLE)
|
||||
kArbitraryRendezvousKey,
|
||||
#elif BUILDFLAG(IS_POSIX)
|
||||
@ -128,7 +127,7 @@ TEST_P(SharedMemorySwitchTest, PassViaSwitch) {
|
||||
#endif
|
||||
&command_line, &launch_options);
|
||||
} else {
|
||||
AddToLaunchParameters(kSharedMemoryData, unsafe_region.Duplicate(),
|
||||
AddToLaunchParameters(kSharedMemoryData, unsafe_region,
|
||||
#if BUILDFLAG(IS_APPLE)
|
||||
kArbitraryRendezvousKey,
|
||||
#elif BUILDFLAG(IS_POSIX)
|
||||
|
@ -627,7 +627,7 @@ std::string FieldTrialList::AllParamsToString(EscapeDataFunc encode_data_func) {
|
||||
if (params_associator->GetFieldTrialParamsWithoutFallback(
|
||||
*trial.trial_name, *trial.group_name, ¶ms)) {
|
||||
if (params.size() > 0) {
|
||||
// Add comma to seprate from previous entry if it exists.
|
||||
// Add comma to separate from previous entry if it exists.
|
||||
if (!output.empty()) {
|
||||
output.append(1, ',');
|
||||
}
|
||||
@ -760,15 +760,14 @@ void FieldTrialList::PopulateLaunchOptionsWithFieldTrialState(
|
||||
CHECK(global_->readonly_allocator_region_.IsValid());
|
||||
|
||||
global_->field_trial_allocator_->UpdateTrackingHistograms();
|
||||
shared_memory::AddToLaunchParameters(
|
||||
switches::kFieldTrialHandle,
|
||||
global_->readonly_allocator_region_.Duplicate(),
|
||||
shared_memory::AddToLaunchParameters(switches::kFieldTrialHandle,
|
||||
global_->readonly_allocator_region_,
|
||||
#if BUILDFLAG(IS_APPLE)
|
||||
kFieldTrialRendezvousKey,
|
||||
kFieldTrialRendezvousKey,
|
||||
#elif BUILDFLAG(IS_POSIX)
|
||||
descriptor_key, descriptor_to_share,
|
||||
descriptor_key, descriptor_to_share,
|
||||
#endif
|
||||
command_line, launch_options);
|
||||
command_line, launch_options);
|
||||
|
||||
// Append --enable-features and --disable-features switches corresponding
|
||||
// to the features enabled on the command-line, so that child and browser
|
||||
|
@ -115,8 +115,7 @@ HistogramSharedMemory::Create(int process_id,
|
||||
}
|
||||
|
||||
// static
|
||||
bool HistogramSharedMemory::PassOnCommandLineIsEnabled(
|
||||
std::string_view process_type) {
|
||||
bool HistogramSharedMemory::PassOnCommandLineIsEnabled(int process_type) {
|
||||
// On ChromeOS and for "utility" processes on other platforms there seems to
|
||||
// be one or more mechanisms on startup which walk through all inherited
|
||||
// shared memory regions and take a read-only handle to them. When we later
|
||||
@ -127,40 +126,32 @@ bool HistogramSharedMemory::PassOnCommandLineIsEnabled(
|
||||
// Example: The call to OpenSymbolFiles() in base/debug/stack_trace_posix.cc
|
||||
// grabs a read-only handle to the shmem region for some process types.
|
||||
//
|
||||
// TODO(crbug.com/40109064): Fix ChromeOS and utility processes.
|
||||
// TODO(crbug.com/40109064): Fix ChromeOS GPU and Android utility processes.
|
||||
// Constants from content::ProcessType;
|
||||
[[maybe_unused]] constexpr int PROCESS_TYPE_GPU = 9;
|
||||
[[maybe_unused]] constexpr int PROCESS_TYPE_UTILITY = 6;
|
||||
return (FeatureList::IsEnabled(kPassHistogramSharedMemoryOnLaunch)
|
||||
#if BUILDFLAG(IS_CHROMEOS)
|
||||
&& process_type != "gpu-process"
|
||||
&& process_type != PROCESS_TYPE_GPU
|
||||
#elif BUILDFLAG(IS_ANDROID)
|
||||
&& process_type != "utility"
|
||||
&& process_type != PROCESS_TYPE_UTILITY
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
// static
|
||||
void HistogramSharedMemory::AddToLaunchParameters(
|
||||
UnsafeSharedMemoryRegion histogram_shmem_region,
|
||||
const UnsafeSharedMemoryRegion& histogram_shmem_region,
|
||||
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
|
||||
GlobalDescriptors::Key descriptor_key,
|
||||
ScopedFD& descriptor_to_share,
|
||||
#endif
|
||||
CommandLine* command_line,
|
||||
LaunchOptions* launch_options) {
|
||||
CHECK(histogram_shmem_region.IsValid());
|
||||
CHECK(command_line);
|
||||
|
||||
const std::string process_type = command_line->GetSwitchValueASCII("type");
|
||||
const bool enabled = PassOnCommandLineIsEnabled(process_type);
|
||||
|
||||
DVLOG(1) << (enabled ? "A" : "Not a")
|
||||
<< "dding histogram shared memory launch parameters for "
|
||||
<< process_type << " process.";
|
||||
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
shared_memory::AddToLaunchParameters(::switches::kMetricsSharedMemoryHandle,
|
||||
std::move(histogram_shmem_region),
|
||||
histogram_shmem_region,
|
||||
#if BUILDFLAG(IS_APPLE)
|
||||
kRendezvousKey,
|
||||
#elif BUILDFLAG(IS_POSIX)
|
||||
|
@ -85,8 +85,8 @@ struct BASE_EXPORT HistogramSharedMemory {
|
||||
#endif
|
||||
|
||||
// Returns true if passing the shared memory handle via command-line arguments
|
||||
// is enabled.
|
||||
static bool PassOnCommandLineIsEnabled(std::string_view process_type);
|
||||
// is enabled. |process_type| values should come from content:::ProcessType.
|
||||
static bool PassOnCommandLineIsEnabled(int process_type);
|
||||
|
||||
// Updates the launch parameters to share |unsafe_memory_region| to a
|
||||
// child process that is about to be launched. This should be called in the
|
||||
@ -97,7 +97,7 @@ struct BASE_EXPORT HistogramSharedMemory {
|
||||
// caller is expected to transmit the descriptor to the launch flow for the
|
||||
// zygote.
|
||||
static void AddToLaunchParameters(
|
||||
UnsafeSharedMemoryRegion unsafe_memory_region,
|
||||
const UnsafeSharedMemoryRegion& unsafe_memory_region,
|
||||
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
|
||||
GlobalDescriptors::Key descriptor_key,
|
||||
ScopedFD& descriptor_to_share,
|
||||
|
@ -53,34 +53,46 @@ TEST(HistogramSharedMemoryTest, Create) {
|
||||
EXPECT_EQ(kArbitrarySize, shared_memory->allocator->size());
|
||||
}
|
||||
|
||||
TEST(HistogramSharedMemoryTest, PassSharedMemoryRegion_Disabled) {
|
||||
// Ensure the feature is disabled.
|
||||
namespace {
|
||||
// Constants from content::ProcessType;
|
||||
constexpr int PROCESS_TYPE_RENDERER = 3;
|
||||
constexpr int PROCESS_TYPE_GPU = 9;
|
||||
constexpr int PROCESS_TYPE_UTILITY = 6;
|
||||
} // namespace
|
||||
|
||||
TEST(HistogramSharedMemoryTest, PassOnCommandLineIsDisabled) {
|
||||
test::ScopedFeatureList feature_list;
|
||||
feature_list.InitAndDisableFeature(kPassHistogramSharedMemoryOnLaunch);
|
||||
|
||||
// Create a shared memory region to pass.
|
||||
auto memory = UnsafeSharedMemoryRegion::Create(kArbitrarySize);
|
||||
ASSERT_TRUE(memory.IsValid());
|
||||
EXPECT_FALSE(
|
||||
HistogramSharedMemory::PassOnCommandLineIsEnabled(PROCESS_TYPE_RENDERER));
|
||||
EXPECT_FALSE(
|
||||
HistogramSharedMemory::PassOnCommandLineIsEnabled(PROCESS_TYPE_GPU));
|
||||
EXPECT_FALSE(
|
||||
HistogramSharedMemory::PassOnCommandLineIsEnabled(PROCESS_TYPE_UTILITY));
|
||||
}
|
||||
|
||||
// Initialize the command line and launch options.
|
||||
CommandLine command_line = GetMultiProcessTestChildBaseCommandLine();
|
||||
command_line.AppendSwitchASCII("type", "test-child");
|
||||
LaunchOptions launch_options;
|
||||
TEST(HistogramSharedMemoryTest, PassOnCommandLineIsEnabled) {
|
||||
test::ScopedFeatureList feature_list;
|
||||
feature_list.InitAndEnableFeature(kPassHistogramSharedMemoryOnLaunch);
|
||||
|
||||
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
|
||||
ScopedFD descriptor_to_share;
|
||||
#endif
|
||||
EXPECT_TRUE(
|
||||
HistogramSharedMemory::PassOnCommandLineIsEnabled(PROCESS_TYPE_RENDERER));
|
||||
#if BUILDFLAG(IS_CHROMEOS)
|
||||
EXPECT_FALSE(
|
||||
HistogramSharedMemory::PassOnCommandLineIsEnabled(PROCESS_TYPE_GPU));
|
||||
#else // !BUILDFLAG(IS_CHROMEOS)
|
||||
EXPECT_TRUE(
|
||||
HistogramSharedMemory::PassOnCommandLineIsEnabled(PROCESS_TYPE_GPU));
|
||||
#endif // !BUILDFLAG(IS_CHROMEOS)
|
||||
|
||||
// Update the launch parameters.
|
||||
HistogramSharedMemory::AddToLaunchParameters(memory.Duplicate(),
|
||||
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
|
||||
kArbitraryDescriptorKey,
|
||||
descriptor_to_share,
|
||||
#endif // BUILDFLAG(IS_POSIX)
|
||||
&command_line, &launch_options);
|
||||
|
||||
// The metrics shared memory handle should NOT be added to the command line.
|
||||
EXPECT_FALSE(command_line.HasSwitch(switches::kMetricsSharedMemoryHandle));
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
EXPECT_FALSE(
|
||||
HistogramSharedMemory::PassOnCommandLineIsEnabled(PROCESS_TYPE_UTILITY));
|
||||
#else // !BUILDFLAG(IS_ANDROID)
|
||||
EXPECT_TRUE(
|
||||
HistogramSharedMemory::PassOnCommandLineIsEnabled(PROCESS_TYPE_UTILITY));
|
||||
#endif // !BUILDFLAG(IS_ANDROID)
|
||||
}
|
||||
|
||||
MULTIPROCESS_TEST_MAIN(InitFromLaunchParameters) {
|
||||
@ -142,7 +154,7 @@ TEST_P(HistogramSharedMemoryTest, PassSharedMemoryRegion_Enabled) {
|
||||
#endif
|
||||
|
||||
// Update the launch parameters.
|
||||
HistogramSharedMemory::AddToLaunchParameters(memory.Duplicate(),
|
||||
HistogramSharedMemory::AddToLaunchParameters(memory,
|
||||
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
|
||||
kArbitraryDescriptorKey,
|
||||
descriptor_to_share,
|
||||
|
@ -42,7 +42,8 @@ void ChildHistogramFetcherFactoryImpl::CreateFetcher(
|
||||
// global histogram allocator should already by setup. Otherwise, the region
|
||||
// is being passed via this IPC. We need to initialize the global histogram
|
||||
// allocator and the tracking histograms here.
|
||||
if (shared_memory.IsValid() && !base::GlobalHistogramAllocator::Get()) {
|
||||
if (shared_memory.IsValid()) {
|
||||
CHECK(!base::GlobalHistogramAllocator::Get());
|
||||
base::GlobalHistogramAllocator::CreateWithSharedMemoryRegion(shared_memory);
|
||||
// Emit a local histogram, which should not be reported to servers. This is
|
||||
// monitored from the serverside.
|
||||
@ -82,7 +83,7 @@ void ChildHistogramFetcherImpl::GetChildNonPersistentHistogramData(
|
||||
}
|
||||
|
||||
std::vector<std::string> deltas;
|
||||
// "false" to PerpareAndSerializeDeltas() indicates to *not* include
|
||||
// "false" to PrepareAndSerializeDeltas() indicates to *not* include
|
||||
// histograms held in persistent storage on the assumption that they will be
|
||||
// visible to the recipient through other means.
|
||||
histogram_delta_serialization_->PrepareAndSerializeDeltas(&deltas, false);
|
||||
|
@ -347,8 +347,9 @@ void BrowserChildProcessHostImpl::LaunchWithoutExtraCommandLineSwitches(
|
||||
child_process_host_->SetProfilingFile(OpenProfilingFile());
|
||||
#endif
|
||||
|
||||
auto tracing_config_memory_region =
|
||||
tracing::CreateTracingConfigSharedMemory();
|
||||
tracing_config_memory_region_ =
|
||||
MakeRefCounted<base::RefCountedData<base::ReadOnlySharedMemoryRegion>>(
|
||||
tracing::CreateTracingConfigSharedMemory());
|
||||
|
||||
child_process_launcher_ = std::make_unique<ChildProcessLauncher>(
|
||||
std::move(delegate), std::move(cmd_line), data_.id, this,
|
||||
@ -356,8 +357,12 @@ void BrowserChildProcessHostImpl::LaunchWithoutExtraCommandLineSwitches(
|
||||
base::BindRepeating(&BrowserChildProcessHostImpl::OnMojoError,
|
||||
weak_factory_.GetWeakPtr(),
|
||||
base::SingleThreadTaskRunner::GetCurrentDefault()),
|
||||
std::move(file_data), metrics_shared_region_.Duplicate(),
|
||||
std::move(tracing_config_memory_region), terminate_on_shutdown);
|
||||
std::move(file_data),
|
||||
base::HistogramSharedMemory::PassOnCommandLineIsEnabled(
|
||||
data_.process_type)
|
||||
? metrics_shared_region_
|
||||
: nullptr,
|
||||
tracing_config_memory_region_, terminate_on_shutdown);
|
||||
ShareMetricsAllocatorToProcess();
|
||||
|
||||
if (!has_legacy_ipc_channel_)
|
||||
@ -600,28 +605,50 @@ void BrowserChildProcessHostImpl::CreateMetricsAllocator() {
|
||||
<< "; process_type='"
|
||||
<< GetProcessTypeNameInEnglish(data_.process_type) << "'";
|
||||
|
||||
metrics_shared_region_ = std::move(shared_memory->region);
|
||||
metrics_shared_region_ =
|
||||
MakeRefCounted<base::RefCountedData<base::UnsafeSharedMemoryRegion>>(
|
||||
std::move(shared_memory->region));
|
||||
metrics_allocator_ = std::move(shared_memory->allocator);
|
||||
}
|
||||
|
||||
void BrowserChildProcessHostImpl::ShareMetricsAllocatorToProcess() {
|
||||
// Only get histograms from content process types; skip "embedder" process
|
||||
// types.
|
||||
metrics::HistogramController::ChildProcessMode histogram_mode =
|
||||
data_.process_type >= PROCESS_TYPE_CONTENT_END
|
||||
const bool enable_histograms =
|
||||
(data_.process_type >= PROCESS_TYPE_CONTENT_END);
|
||||
|
||||
// Exchange pings from embedder processes; histograms from content processes.
|
||||
const auto histogram_mode =
|
||||
enable_histograms
|
||||
? metrics::HistogramController::ChildProcessMode::kPingOnly
|
||||
: metrics::HistogramController::ChildProcessMode::kGetHistogramData;
|
||||
|
||||
if (metrics_allocator_) {
|
||||
metrics::HistogramController::GetInstance()->SetHistogramMemory(
|
||||
this, std::move(metrics_shared_region_), histogram_mode);
|
||||
DVLOG(1) << "metrics_shared_region_ has been moved: " << "pid=" << data_.id
|
||||
<< "; process_type="
|
||||
<< GetProcessTypeNameInEnglish(data_.process_type);
|
||||
} else {
|
||||
metrics::HistogramController::GetInstance()->SetHistogramMemory(
|
||||
this, base::UnsafeSharedMemoryRegion(), histogram_mode);
|
||||
}
|
||||
// If histograms are enabled, but passing the shared memory region on the
|
||||
// command line is NOT enabled for this process type, then we pass the region
|
||||
// via the child's HistogramController, below; otherwise, we give the
|
||||
// HistogramController a default (invalid) region.
|
||||
// TODO(crbug.com/40818143): simplify to always pass an empty region or to
|
||||
// elide that param once passing the region via the command line is fully
|
||||
// launched for all content process types.
|
||||
auto memory_region =
|
||||
enable_histograms && metrics_shared_region_ &&
|
||||
!base::HistogramSharedMemory::PassOnCommandLineIsEnabled(
|
||||
data_.process_type)
|
||||
? std::move(metrics_shared_region_->data)
|
||||
: base::UnsafeSharedMemoryRegion();
|
||||
|
||||
// Pass the shared memory region to use for future histogram transmission
|
||||
// (an invalid region if the region was already passed via the command line)
|
||||
// and ask the child to transmit any early histograms that did not get stored
|
||||
// in shared memory. This happens exactly once for each child process.
|
||||
metrics::HistogramController::GetInstance()->SetHistogramMemory(
|
||||
this, std::move(memory_region), histogram_mode);
|
||||
|
||||
// At this point the shared memory region has either been shared via command
|
||||
// line, or it has been given (moved) to the histogram controller. The child
|
||||
// process host no longer needs to track it. We can safely release the host's
|
||||
// reference.
|
||||
metrics_shared_region_.reset();
|
||||
}
|
||||
|
||||
void BrowserChildProcessHostImpl::OnProcessLaunchFailed(int error_code) {
|
||||
@ -662,7 +689,7 @@ void BrowserChildProcessHostImpl::OnProcessLaunched() {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
// Start a WaitableEventWatcher that will invoke OnProcessExitedEarly if the
|
||||
// child process exits. This watcher is stopped once the IPC channel is
|
||||
// connected and the exit of the child process is detecter by an error on the
|
||||
// connected and the exit of the child process is detected by an error on the
|
||||
// IPC channel thereafter.
|
||||
DCHECK(!early_exit_watcher_.GetWatchedObject());
|
||||
early_exit_watcher_.StartWatchingOnce(process.Handle(), this);
|
||||
|
@ -230,9 +230,20 @@ class BrowserChildProcessHostImpl
|
||||
// The memory allocator, if any, in which the process will write its metrics.
|
||||
std::unique_ptr<base::PersistentMemoryAllocator> metrics_allocator_;
|
||||
|
||||
// The shared memory region used by |metrics_allocator_| that should be
|
||||
// transferred to the child process.
|
||||
base::UnsafeSharedMemoryRegion metrics_shared_region_;
|
||||
// The histogram shared memory region used to transmit metrics. The memory
|
||||
// region is allocated by the process host (this object) but ownership is
|
||||
// shared with the child process launcher/helper which runs, and is destroyed,
|
||||
// asynchronously. Depending on the feature configuration, either the host or
|
||||
// the launcher is responsible for passing the memory region to the child.
|
||||
// The destruction order of the host, launcher and child are indeterminate.
|
||||
scoped_refptr<base::RefCountedData<base::UnsafeSharedMemoryRegion>>
|
||||
metrics_shared_region_;
|
||||
|
||||
// The tracing config memory region. Ownership of the memory region object is
|
||||
// shared with the child process launcher/helper which runs, and is destroyed,
|
||||
// asynchronously.
|
||||
scoped_refptr<base::RefCountedData<base::ReadOnlySharedMemoryRegion>>
|
||||
tracing_config_memory_region_;
|
||||
|
||||
// Indicates if the main browser process is used instead of a dedicated child
|
||||
// process.
|
||||
|
@ -100,8 +100,10 @@ ChildProcessLauncher::ChildProcessLauncher(
|
||||
mojo::OutgoingInvitation mojo_invitation,
|
||||
const mojo::ProcessErrorCallback& process_error_callback,
|
||||
std::unique_ptr<ChildProcessLauncherFileData> file_data,
|
||||
base::UnsafeSharedMemoryRegion histogram_memory_region,
|
||||
base::ReadOnlySharedMemoryRegion tracing_config_memory_region,
|
||||
scoped_refptr<base::RefCountedData<base::UnsafeSharedMemoryRegion>>
|
||||
histogram_memory_region,
|
||||
scoped_refptr<base::RefCountedData<base::ReadOnlySharedMemoryRegion>>
|
||||
tracing_config_memory_region,
|
||||
bool terminate_on_shutdown)
|
||||
: client_(client),
|
||||
starting_(true),
|
||||
|
@ -245,8 +245,10 @@ class CONTENT_EXPORT ChildProcessLauncher {
|
||||
mojo::OutgoingInvitation mojo_invitation,
|
||||
const mojo::ProcessErrorCallback& process_error_callback,
|
||||
std::unique_ptr<ChildProcessLauncherFileData> file_data,
|
||||
base::UnsafeSharedMemoryRegion = {},
|
||||
base::ReadOnlySharedMemoryRegion = {},
|
||||
scoped_refptr<base::RefCountedData<base::UnsafeSharedMemoryRegion>>
|
||||
histogram_memory_region = nullptr,
|
||||
scoped_refptr<base::RefCountedData<base::ReadOnlySharedMemoryRegion>>
|
||||
trace_config_memory_region = nullptr,
|
||||
bool terminate_on_shutdown = true);
|
||||
|
||||
ChildProcessLauncher(const ChildProcessLauncher&) = delete;
|
||||
@ -262,7 +264,7 @@ class CONTENT_EXPORT ChildProcessLauncher {
|
||||
|
||||
// Call this when the child process exits to know what happened to it.
|
||||
// |known_dead| can be true if we already know the process is dead as it can
|
||||
// help the implemention figure the proper TerminationStatus.
|
||||
// help the implementation figure the proper TerminationStatus.
|
||||
// On Linux, the use of |known_dead| is subtle and can be crucial if an
|
||||
// accurate status is important. With |known_dead| set to false, a dead
|
||||
// process could be seen as running. With |known_dead| set to true, the
|
||||
|
@ -68,18 +68,13 @@ void RecordHistogramsOnLauncherThread(base::TimeDelta launch_time) {
|
||||
//
|
||||
// This function is NOP if the platform does not use Blink.
|
||||
void PassHistogramSharedMemoryHandle(
|
||||
[[maybe_unused]] base::UnsafeSharedMemoryRegion histogram_memory_region,
|
||||
[[maybe_unused]] const base::UnsafeSharedMemoryRegion*
|
||||
histogram_memory_region,
|
||||
[[maybe_unused]] base::CommandLine* command_line,
|
||||
[[maybe_unused]] base::LaunchOptions* launch_options,
|
||||
[[maybe_unused]] FileMappedForLaunch* files_to_register) {
|
||||
// TODO(crbug.com/40109064): Once all process types support histogram shared
|
||||
// memory being passed at launch, remove this if.
|
||||
if (!histogram_memory_region.IsValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if BUILDFLAG(USE_BLINK)
|
||||
CHECK(command_line);
|
||||
CHECK(histogram_memory_region.IsValid());
|
||||
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
|
||||
// TODO(crbug.com/40109064): content::FileMappedForLaunch (POSIX) is redundant
|
||||
// wrt the base::LaunchOptions::<platform-specific-handles-to-transfer>
|
||||
@ -94,12 +89,21 @@ void PassHistogramSharedMemoryHandle(
|
||||
base::ScopedFD descriptor_to_transfer;
|
||||
#else
|
||||
CHECK(launch_options);
|
||||
#endif
|
||||
#endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
|
||||
|
||||
#if BUILDFLAG(USE_BLINK)
|
||||
DCHECK(histogram_memory_region.IsValid());
|
||||
// TODO(crbug.com/40109064): Once all process types support histogram shared
|
||||
// memory being passed at launch, remove this if.
|
||||
const bool enabled =
|
||||
histogram_memory_region && histogram_memory_region->IsValid();
|
||||
DVLOG(1) << (enabled ? "A" : "Not a")
|
||||
<< "dding histogram shared memory launch parameters for "
|
||||
<< command_line->GetSwitchValueASCII(::switches::kProcessType)
|
||||
<< " process.";
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
base::HistogramSharedMemory::AddToLaunchParameters(
|
||||
std::move(histogram_memory_region),
|
||||
*histogram_memory_region,
|
||||
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
|
||||
/*descriptor_key=*/kHistogramSharedMemoryDescriptor,
|
||||
/*descriptor_to_share=*/descriptor_to_transfer,
|
||||
@ -123,6 +127,7 @@ void PassFieldTrialSharedMemoryHandle(
|
||||
[[maybe_unused]] base::CommandLine* command_line,
|
||||
[[maybe_unused]] base::LaunchOptions* launch_options,
|
||||
[[maybe_unused]] FileMappedForLaunch* files_to_register) {
|
||||
#if BUILDFLAG(USE_BLINK)
|
||||
CHECK(command_line);
|
||||
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
|
||||
// TODO(crbug.com/40109064): content::FileMappedForLaunch (POSIX) is redundant
|
||||
@ -140,7 +145,6 @@ void PassFieldTrialSharedMemoryHandle(
|
||||
CHECK(launch_options);
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(USE_BLINK)
|
||||
variations::PopulateLaunchOptionsWithVariationsInfo(
|
||||
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
|
||||
/*descriptor_key=*/kFieldTrialDescriptor,
|
||||
@ -158,16 +162,17 @@ void PassFieldTrialSharedMemoryHandle(
|
||||
}
|
||||
|
||||
void PassStartupTracingConfigSharedMemoryHandle(
|
||||
[[maybe_unused]] base::ReadOnlySharedMemoryRegion read_only_memory_region,
|
||||
[[maybe_unused]] const base::ReadOnlySharedMemoryRegion*
|
||||
read_only_memory_region,
|
||||
[[maybe_unused]] base::CommandLine* command_line,
|
||||
[[maybe_unused]] base::LaunchOptions* launch_options,
|
||||
[[maybe_unused]] FileMappedForLaunch* files_to_register) {
|
||||
#if BUILDFLAG(USE_BLINK)
|
||||
CHECK(command_line);
|
||||
if (!read_only_memory_region.IsValid()) {
|
||||
if (!read_only_memory_region || !read_only_memory_region->IsValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
CHECK(read_only_memory_region.IsValid());
|
||||
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
|
||||
CHECK(files_to_register);
|
||||
base::ScopedFD descriptor_to_transfer;
|
||||
@ -175,12 +180,11 @@ void PassStartupTracingConfigSharedMemoryHandle(
|
||||
CHECK(launch_options);
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(USE_BLINK)
|
||||
tracing::AddTraceConfigToLaunchParameters(std::move(read_only_memory_region),
|
||||
tracing::AddTraceConfigToLaunchParameters(*read_only_memory_region,
|
||||
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
|
||||
kTraceConfigSharedMemoryDescriptor,
|
||||
descriptor_to_transfer,
|
||||
#endif
|
||||
#endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
|
||||
command_line, launch_options);
|
||||
|
||||
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
|
||||
@ -227,8 +231,10 @@ ChildProcessLauncherHelper::ChildProcessLauncherHelper(
|
||||
mojo::OutgoingInvitation mojo_invitation,
|
||||
const mojo::ProcessErrorCallback& process_error_callback,
|
||||
std::unique_ptr<ChildProcessLauncherFileData> file_data,
|
||||
base::UnsafeSharedMemoryRegion histogram_memory_region,
|
||||
base::ReadOnlySharedMemoryRegion tracing_config_memory_region)
|
||||
scoped_refptr<base::RefCountedData<base::UnsafeSharedMemoryRegion>>
|
||||
histogram_memory_region,
|
||||
scoped_refptr<base::RefCountedData<base::ReadOnlySharedMemoryRegion>>
|
||||
tracing_config_memory_region)
|
||||
: child_process_id_(child_process_id),
|
||||
client_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()),
|
||||
command_line_(std::move(command_line)),
|
||||
@ -314,14 +320,15 @@ void ChildProcessLauncherHelper::LaunchOnLauncherThread() {
|
||||
|
||||
// Update the command line and launch options to pass the histogram and
|
||||
// field trial shared memory region handles.
|
||||
PassHistogramSharedMemoryHandle(std::move(histogram_memory_region_),
|
||||
command_line(), options_ptr,
|
||||
files_to_register.get());
|
||||
PassHistogramSharedMemoryHandle(
|
||||
histogram_memory_region_ ? &histogram_memory_region_->data : nullptr,
|
||||
command_line(), options_ptr, files_to_register.get());
|
||||
PassFieldTrialSharedMemoryHandle(command_line(), options_ptr,
|
||||
files_to_register.get());
|
||||
PassStartupTracingConfigSharedMemoryHandle(
|
||||
std::move(tracing_config_memory_region_), command_line(), options_ptr,
|
||||
files_to_register.get());
|
||||
tracing_config_memory_region_ ? &tracing_config_memory_region_->data
|
||||
: nullptr,
|
||||
command_line(), options_ptr, files_to_register.get());
|
||||
|
||||
// Transfer logging switches & handles if necessary.
|
||||
PassLoggingSwitches(options_ptr, command_line());
|
||||
|
@ -133,8 +133,10 @@ class ChildProcessLauncherHelper
|
||||
mojo::OutgoingInvitation mojo_invitation,
|
||||
const mojo::ProcessErrorCallback& process_error_callback,
|
||||
std::unique_ptr<ChildProcessLauncherFileData> file_data,
|
||||
base::UnsafeSharedMemoryRegion histogram_memory_region,
|
||||
base::ReadOnlySharedMemoryRegion tracing_config_memory_region);
|
||||
scoped_refptr<base::RefCountedData<base::UnsafeSharedMemoryRegion>>
|
||||
histogram_memory_region,
|
||||
scoped_refptr<base::RefCountedData<base::ReadOnlySharedMemoryRegion>>
|
||||
tracing_config_memory_region);
|
||||
|
||||
// The methods below are defined in the order they are called.
|
||||
|
||||
@ -354,11 +356,16 @@ class ChildProcessLauncherHelper
|
||||
base::win::ScopedHandle log_handle_;
|
||||
#endif
|
||||
|
||||
// Histogram shared memory region metadata.
|
||||
base::UnsafeSharedMemoryRegion histogram_memory_region_;
|
||||
// Histogram shared memory region. Ownership of the memory region object is
|
||||
// shared with the process host which runs, and is destroyed, asynchronously.
|
||||
scoped_refptr<base::RefCountedData<base::UnsafeSharedMemoryRegion>>
|
||||
histogram_memory_region_;
|
||||
|
||||
// Startup tracing config shared memory region.
|
||||
base::ReadOnlySharedMemoryRegion tracing_config_memory_region_;
|
||||
// Startup tracing config shared memory region. Ownership of the memory region
|
||||
// object is shared with the process host which runs, and is destroyed,
|
||||
// asynchronously.
|
||||
scoped_refptr<base::RefCountedData<base::ReadOnlySharedMemoryRegion>>
|
||||
tracing_config_memory_region_;
|
||||
|
||||
// Creation time of the helper, used for metrics.
|
||||
// TODO(crbug.com/40287847): Remove when parallel launching is finished.
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "base/metrics/histogram_shared_memory.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "content/public/common/process_type.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
@ -14,6 +16,7 @@ namespace content {
|
||||
namespace {
|
||||
|
||||
using Config = base::HistogramSharedMemory::Config;
|
||||
using base::HistogramSharedMemory;
|
||||
|
||||
struct ProcessTypeToOptionalConfig {
|
||||
int process_type;
|
||||
@ -31,6 +34,42 @@ using HistogramSharedMemoryConfigTest =
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(HistogramSharedMemoryConfigTest, PassOnCommandLineIsDisabled) {
|
||||
base::test::ScopedFeatureList feature_list;
|
||||
feature_list.InitAndDisableFeature(base::kPassHistogramSharedMemoryOnLaunch);
|
||||
|
||||
EXPECT_FALSE(
|
||||
HistogramSharedMemory::PassOnCommandLineIsEnabled(PROCESS_TYPE_RENDERER));
|
||||
EXPECT_FALSE(
|
||||
HistogramSharedMemory::PassOnCommandLineIsEnabled(PROCESS_TYPE_GPU));
|
||||
EXPECT_FALSE(
|
||||
HistogramSharedMemory::PassOnCommandLineIsEnabled(PROCESS_TYPE_UTILITY));
|
||||
}
|
||||
|
||||
TEST(HistogramSharedMemoryConfigTest, PassOnCommandLineIsEnabled) {
|
||||
base::test::ScopedFeatureList feature_list;
|
||||
feature_list.InitAndEnableFeature(base::kPassHistogramSharedMemoryOnLaunch);
|
||||
|
||||
EXPECT_TRUE(
|
||||
HistogramSharedMemory::PassOnCommandLineIsEnabled(PROCESS_TYPE_RENDERER));
|
||||
|
||||
#if BUILDFLAG(IS_CHROMEOS)
|
||||
EXPECT_FALSE(
|
||||
HistogramSharedMemory::PassOnCommandLineIsEnabled(PROCESS_TYPE_GPU));
|
||||
#else // !BUILDFLAG(IS_CHROMEOS)
|
||||
EXPECT_TRUE(
|
||||
HistogramSharedMemory::PassOnCommandLineIsEnabled(PROCESS_TYPE_GPU));
|
||||
#endif // !BUILDFLAG(IS_CHROMEOS)
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
EXPECT_FALSE(
|
||||
HistogramSharedMemory::PassOnCommandLineIsEnabled(PROCESS_TYPE_UTILITY));
|
||||
#else // !BUILDFLAG(IS_ANDROID)
|
||||
EXPECT_TRUE(
|
||||
HistogramSharedMemory::PassOnCommandLineIsEnabled(PROCESS_TYPE_UTILITY));
|
||||
#endif // !BUILDFLAG(IS_ANDROID)
|
||||
}
|
||||
|
||||
TEST_P(HistogramSharedMemoryConfigTest, GetHistogramSharedMemoryConfig) {
|
||||
const auto& process_type = GetParam().process_type;
|
||||
const auto& expected = GetParam().expected;
|
||||
|
@ -1772,8 +1772,9 @@ bool RenderProcessHostImpl::Init() {
|
||||
std::make_unique<RendererSandboxedProcessLauncherDelegate>();
|
||||
#endif
|
||||
|
||||
auto tracing_config_memory_region =
|
||||
tracing::CreateTracingConfigSharedMemory();
|
||||
tracing_config_memory_region_ =
|
||||
MakeRefCounted<base::RefCountedData<base::ReadOnlySharedMemoryRegion>>(
|
||||
tracing::CreateTracingConfigSharedMemory());
|
||||
|
||||
auto file_data = std::make_unique<ChildProcessLauncherFileData>();
|
||||
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
|
||||
@ -1787,8 +1788,12 @@ bool RenderProcessHostImpl::Init() {
|
||||
std::move(sandbox_delegate), std::move(cmd_line), GetDeprecatedID(),
|
||||
this, std::move(mojo_invitation_),
|
||||
base::BindRepeating(&RenderProcessHostImpl::OnMojoError, id_),
|
||||
std::move(file_data), metrics_memory_region_.Duplicate(),
|
||||
std::move(tracing_config_memory_region));
|
||||
std::move(file_data),
|
||||
base::HistogramSharedMemory::PassOnCommandLineIsEnabled(
|
||||
PROCESS_TYPE_RENDERER)
|
||||
? metrics_memory_region_
|
||||
: nullptr,
|
||||
tracing_config_memory_region_);
|
||||
channel_->Pause();
|
||||
|
||||
// In single process mode, browser-side tracing and memory will cover the
|
||||
@ -4931,15 +4936,40 @@ void RenderProcessHostImpl::CreateMetricsAllocator() {
|
||||
auto shared_memory = base::HistogramSharedMemory::Create(
|
||||
GetDeprecatedID(), shared_memory_config.value());
|
||||
if (shared_memory.has_value()) {
|
||||
metrics_memory_region_ = std::move(shared_memory->region);
|
||||
metrics_memory_region_ =
|
||||
MakeRefCounted<base::RefCountedData<base::UnsafeSharedMemoryRegion>>(
|
||||
std::move(shared_memory->region));
|
||||
metrics_allocator_ = std::move(shared_memory->allocator);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderProcessHostImpl::ShareMetricsMemoryRegion() {
|
||||
// If passing the shared memory region on the command line is NOT enabled
|
||||
// then we pass it here via the renderer's HistogramController; otherwise,
|
||||
// give the HistogramController a default (invalid) region.
|
||||
// TODO(crbug.com/40818143): simplify to always pass an empty region or to
|
||||
// elide that param once passing the region via the command line if fully
|
||||
// launched.
|
||||
auto memory_region =
|
||||
metrics_memory_region_ &&
|
||||
!base::HistogramSharedMemory::PassOnCommandLineIsEnabled(
|
||||
PROCESS_TYPE_RENDERER)
|
||||
? std::move(metrics_memory_region_->data)
|
||||
: base::UnsafeSharedMemoryRegion();
|
||||
|
||||
// Pass the shared memory region to use for future histogram transmission
|
||||
// (an invalid region if the region was already passed via the command line)
|
||||
// and ask the renderer to transmit any early histograms that did not get
|
||||
// stored in shared memory. This happens exactly once for each render process.
|
||||
metrics::HistogramController::GetInstance()->SetHistogramMemory(
|
||||
this, std::move(metrics_memory_region_),
|
||||
this, std::move(memory_region),
|
||||
metrics::HistogramController::ChildProcessMode::kGetHistogramData);
|
||||
|
||||
// At this point the shared memory region has either been shared via command
|
||||
// line, or it has been given (moved) to the histogram controller. The render
|
||||
// process host no longer needs to track it. We can safely release the host's
|
||||
// reference.
|
||||
metrics_memory_region_.reset();
|
||||
}
|
||||
|
||||
ChildProcessTerminationInfo RenderProcessHostImpl::GetChildTerminationInfo(
|
||||
@ -5015,7 +5045,7 @@ void RenderProcessHostImpl::ProcessDied(
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize a new ChannelProxy in case this host is re-used for a new
|
||||
// Initialize a new ChannelProxy in case this host is reused for a new
|
||||
// process. This ensures that new messages can be sent on the host ASAP
|
||||
// (even before Init()) and they'll eventually reach the new process.
|
||||
//
|
||||
@ -5264,7 +5294,7 @@ void RenderProcessHostImpl::UpdateProcessPriority() {
|
||||
if (!run_renderer_in_process() && (!child_process_launcher_.get() ||
|
||||
child_process_launcher_->IsStarting())) {
|
||||
// This path can be hit early (no-op) or on ProcessDied(). Reset
|
||||
// |priority_| to defaults in case this RenderProcessHostImpl is re-used.
|
||||
// |priority_| to defaults in case this RenderProcessHostImpl is reused.
|
||||
priority_.visible = !blink::kLaunchingProcessIsBackgrounded;
|
||||
priority_.boost_for_pending_views = true;
|
||||
return;
|
||||
|
@ -748,7 +748,7 @@ class CONTENT_EXPORT RenderProcessHostImpl
|
||||
void BindWebrtcVideoPerfHistory(
|
||||
mojo::PendingReceiver<media::mojom::WebrtcVideoPerfHistory> receiver);
|
||||
|
||||
// Binds `receiever` to the `PushMessagingManager` instance owned by the
|
||||
// Binds `receiver` to the `PushMessagingManager` instance owned by the
|
||||
// render process host, and is used by workers via `BrowserInterfaceBroker`.
|
||||
void BindPushMessaging(
|
||||
mojo::PendingReceiver<blink::mojom::PushMessaging> receiver);
|
||||
@ -1456,7 +1456,21 @@ class CONTENT_EXPORT RenderProcessHostImpl
|
||||
|
||||
// The memory allocator, if any, in which the renderer will write its metrics.
|
||||
std::unique_ptr<base::PersistentMemoryAllocator> metrics_allocator_;
|
||||
base::UnsafeSharedMemoryRegion metrics_memory_region_;
|
||||
|
||||
// The histogram shared memory region used to transmit metrics. The memory
|
||||
// region is allocated by the process host (this object) but ownership is
|
||||
// shared with the child process launcher/helper which runs, and is destroyed,
|
||||
// asynchronously. Depending on the feature configuration, either the host or
|
||||
// the launcher is responsible for passing the memory region to the child.
|
||||
// The destruction order of the host, launcher and child are indeterminate.
|
||||
scoped_refptr<base::RefCountedData<base::UnsafeSharedMemoryRegion>>
|
||||
metrics_memory_region_;
|
||||
|
||||
// The tracing config memory region. The memory region is allocated by the
|
||||
// process host (this object) but ownership is shared with the child process
|
||||
// launcher/helper which runs, and is destroyed, asynchronously.
|
||||
scoped_refptr<base::RefCountedData<base::ReadOnlySharedMemoryRegion>>
|
||||
tracing_config_memory_region_;
|
||||
|
||||
bool channel_connected_ = false;
|
||||
bool sent_render_process_ready_ = false;
|
||||
|
@ -146,7 +146,7 @@ base::ReadOnlySharedMemoryRegion CreateTracingConfigSharedMemory() {
|
||||
}
|
||||
|
||||
void COMPONENT_EXPORT(TRACING_CPP) AddTraceConfigToLaunchParameters(
|
||||
base::ReadOnlySharedMemoryRegion read_only_memory_region,
|
||||
const base::ReadOnlySharedMemoryRegion& read_only_memory_region,
|
||||
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
|
||||
base::GlobalDescriptors::Key descriptor_key,
|
||||
base::ScopedFD& out_descriptor_to_share,
|
||||
@ -154,7 +154,7 @@ void COMPONENT_EXPORT(TRACING_CPP) AddTraceConfigToLaunchParameters(
|
||||
base::CommandLine* command_line,
|
||||
base::LaunchOptions* launch_options) {
|
||||
base::shared_memory::AddToLaunchParameters(switches::kTraceConfigHandle,
|
||||
std::move(read_only_memory_region),
|
||||
read_only_memory_region,
|
||||
#if BUILDFLAG(IS_APPLE)
|
||||
kTraceConfigRendezvousKey,
|
||||
#elif BUILDFLAG(IS_POSIX)
|
||||
|
@ -65,7 +65,7 @@ base::ReadOnlySharedMemoryRegion COMPONENT_EXPORT(TRACING_CPP)
|
||||
// flags and launch options, given a SMB config obtained with
|
||||
// CreateTracingConfigSharedMemory().
|
||||
void COMPONENT_EXPORT(TRACING_CPP) AddTraceConfigToLaunchParameters(
|
||||
base::ReadOnlySharedMemoryRegion,
|
||||
const base::ReadOnlySharedMemoryRegion& read_only_memory_region,
|
||||
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
|
||||
base::GlobalDescriptors::Key descriptor_key,
|
||||
base::ScopedFD& out_descriptor_to_share,
|
||||
|
Reference in New Issue
Block a user