File: histogram_shared_memory.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (198 lines) | stat: -rw-r--r-- 7,148 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/metrics/histogram_shared_memory.h"

#include <string_view>

#include "base/base_switches.h"
#include "base/debug/crash_logging.h"
#include "base/logging.h"
#include "base/memory/shared_memory_mapping.h"
#include "base/memory/writable_shared_memory_region.h"
#include "base/metrics/histogram_macros_local.h"
#include "base/metrics/persistent_histogram_allocator.h"
#include "base/metrics/persistent_memory_allocator.h"
#include "base/process/launch.h"
#include "base/process/process_handle.h"
#include "base/process/process_info.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/unguessable_token.h"

// On Apple platforms, the shared memory handle is shared using a Mach port
// rendezvous key.
#if BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_IOS_TVOS)
#include "base/apple/mach_port_rendezvous.h"
#endif

// On POSIX, the shared memory handle is a file_descriptor mapped in the
// GlobalDescriptors table.
#if BUILDFLAG(IS_POSIX)
#include "base/posix/global_descriptors.h"
#endif

#if BUILDFLAG(IS_WIN)
#include <windows.h>

#include "base/win/win_util.h"
#endif

#if BUILDFLAG(IS_FUCHSIA)
#include <lib/zx/vmo.h>
#include <zircon/process.h>

#include "base/fuchsia/fuchsia_logging.h"
#endif

// This file supports passing a read/write histogram shared memory region
// between a parent process and child process. The information about the
// shared memory region is encoded into a command-line switch value.
//
// Format: "handle,[irp],guid-high,guid-low,size".
//
// The switch value is composed of 5 segments, separated by commas:
//
// 1. The platform-specific handle id for the shared memory as a string.
// 2. [irp] to indicate whether the handle is inherited (i, most platforms),
//    sent via rendezvous (r, MacOS), or should be queried from the parent
//    (p, Windows).
// 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/40109064): Refactor the common logic here and in
// base/metrics/field_trial.cc
namespace base {

BASE_FEATURE(kPassHistogramSharedMemoryOnLaunch,
             "PassHistogramSharedMemoryOnLaunch",
#if BUILDFLAG(IS_ANDROID)
             FEATURE_DISABLED_BY_DEFAULT
#else
             FEATURE_ENABLED_BY_DEFAULT
#endif
);

#if BUILDFLAG(IS_APPLE)
const shared_memory::SharedMemoryMachPortRendezvousKey
    HistogramSharedMemory::kRendezvousKey = 'hsmr';
#endif

HistogramSharedMemory::SharedMemory::SharedMemory(
    UnsafeSharedMemoryRegion r,
    std::unique_ptr<PersistentMemoryAllocator> a)
    : region(std::move(r)), allocator(std::move(a)) {
  CHECK(region.IsValid());
  CHECK(allocator);
}

HistogramSharedMemory::SharedMemory::~SharedMemory() = default;

HistogramSharedMemory::SharedMemory::SharedMemory(
    HistogramSharedMemory::SharedMemory&&) = default;

HistogramSharedMemory::SharedMemory&
HistogramSharedMemory::SharedMemory::operator=(
    HistogramSharedMemory::SharedMemory&&) = default;

// static
std::optional<HistogramSharedMemory::SharedMemory>
HistogramSharedMemory::Create(int process_id,
                              const HistogramSharedMemory::Config& config) {
  auto region = UnsafeSharedMemoryRegion::Create(config.memory_size_bytes);
  if (!region.IsValid()) {
    DVLOG(1) << "Failed to create shared memory region.";
    return std::nullopt;
  }
  auto mapping = region.Map();
  if (!mapping.IsValid()) {
    DVLOG(1) << "Failed to create shared memory mapping.";
    return std::nullopt;
  }

  return SharedMemory{std::move(region),
                      std::make_unique<WritableSharedPersistentMemoryAllocator>(
                          std::move(mapping), static_cast<uint64_t>(process_id),
                          config.allocator_name)};
}

// static
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
  // attempt to deserialize the handle info and take a writable handle we
  // find that the handle is already owned in read-only mode, triggering
  // a crash due to "FD ownership violation".
  //
  // 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 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 != PROCESS_TYPE_GPU
#elif BUILDFLAG(IS_ANDROID)
          && process_type != PROCESS_TYPE_UTILITY
#endif
  );
}

// static
void HistogramSharedMemory::AddToLaunchParameters(
    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);
  shared_memory::AddToLaunchParameters(::switches::kMetricsSharedMemoryHandle,
                                       histogram_shmem_region,
#if BUILDFLAG(IS_APPLE)
                                       kRendezvousKey,
#elif BUILDFLAG(IS_POSIX)
                                       descriptor_key, descriptor_to_share,
#endif
                                       command_line, launch_options);
}

// static
void HistogramSharedMemory::InitFromLaunchParameters(
    const CommandLine& command_line) {
  // TODO(crbug.com/40109064): Clean up once fully launched.
  if (!command_line.HasSwitch(switches::kMetricsSharedMemoryHandle)) {
    return;
  }
  CHECK(!GlobalHistogramAllocator::Get());
  DVLOG(1) << "Initializing histogram shared memory from command line for "
           << command_line.GetSwitchValueASCII("type");

  auto shmem_region = shared_memory::UnsafeSharedMemoryRegionFrom(
      command_line.GetSwitchValueASCII(switches::kMetricsSharedMemoryHandle));

  SCOPED_CRASH_KEY_NUMBER(
      "HistogramAllocator", "SharedMemError",
      static_cast<int>(shmem_region.has_value()
                           ? shared_memory::SharedMemoryError::kNoError
                           : shmem_region.error()));

  CHECK(shmem_region.has_value() && shmem_region.value().IsValid())
      << "Invald memory region passed on command line.";

  GlobalHistogramAllocator::CreateWithSharedMemoryRegion(shmem_region.value());

  auto* global_allocator = GlobalHistogramAllocator::Get();
  CHECK(global_allocator);
  global_allocator->CreateTrackingHistograms(global_allocator->Name());
}

}  // namespace base