summaryrefslogtreecommitdiff
path: root/chromium/base/metrics
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-13 15:05:36 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-14 10:33:47 +0000
commite684a3455bcc29a6e3e66a004e352dea4e1141e7 (patch)
treed55b4003bde34d7d05f558f02cfd82b2a66a7aac /chromium/base/metrics
parent2b94bfe47ccb6c08047959d1c26e392919550e86 (diff)
downloadqtwebengine-chromium-e684a3455bcc29a6e3e66a004e352dea4e1141e7.tar.gz
BASELINE: Update Chromium to 72.0.3626.110 and Ninja to 1.9.0
Change-Id: Ic57220b00ecc929a893c91f5cc552f5d3e99e922 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/base/metrics')
-rw-r--r--chromium/base/metrics/OWNERS3
-rw-r--r--chromium/base/metrics/bucket_ranges.cc3
-rw-r--r--chromium/base/metrics/bucket_ranges.h1
-rw-r--r--chromium/base/metrics/field_trial.cc152
-rw-r--r--chromium/base/metrics/field_trial.h18
-rw-r--r--chromium/base/metrics/field_trial_memory_mac.cc206
-rw-r--r--chromium/base/metrics/field_trial_memory_mac.h85
-rw-r--r--chromium/base/metrics/field_trial_memory_mac_unittest.cc118
-rw-r--r--chromium/base/metrics/field_trial_unittest.cc76
-rw-r--r--chromium/base/metrics/histogram.cc44
-rw-r--r--chromium/base/metrics/histogram_flattener.h3
-rw-r--r--chromium/base/metrics/histogram_functions.cc16
-rw-r--r--chromium/base/metrics/histogram_functions.h13
-rw-r--r--chromium/base/metrics/histogram_macros.h24
-rw-r--r--chromium/base/metrics/histogram_macros_local.h6
-rw-r--r--chromium/base/metrics/histogram_unittest.cc19
-rw-r--r--chromium/base/metrics/persistent_histogram_storage.cc2
-rw-r--r--chromium/base/metrics/persistent_histogram_storage_unittest.cc5
-rw-r--r--chromium/base/metrics/persistent_memory_allocator.cc15
-rw-r--r--chromium/base/metrics/user_metrics.cc2
20 files changed, 670 insertions, 141 deletions
diff --git a/chromium/base/metrics/OWNERS b/chromium/base/metrics/OWNERS
index 4cc69ff0630..5ed8a4a263c 100644
--- a/chromium/base/metrics/OWNERS
+++ b/chromium/base/metrics/OWNERS
@@ -1,10 +1,11 @@
asvitkine@chromium.org
bcwhite@chromium.org
-gayane@chromium.org
holte@chromium.org
isherman@chromium.org
jwd@chromium.org
mpearson@chromium.org
rkaplow@chromium.org
+per-file field_trial_memory_mac*=rsesek@chromium.org
+
# COMPONENT: Internals>Metrics
diff --git a/chromium/base/metrics/bucket_ranges.cc b/chromium/base/metrics/bucket_ranges.cc
index 39b379320e6..2723c3eb35a 100644
--- a/chromium/base/metrics/bucket_ranges.cc
+++ b/chromium/base/metrics/bucket_ranges.cc
@@ -74,7 +74,8 @@ const uint32_t kCrcTable[256] = {
// the CRC correct for big-endian vs little-ending calculations. All we need is
// a nice hash, that tends to depend on all the bits of the sample, with very
// little chance of changes in one place impacting changes in another place.
-static uint32_t Crc32(uint32_t sum, HistogramBase::Sample value) {
+// Temporary non-static for https://crbug.com/836238
+/*static*/ uint32_t Crc32(uint32_t sum, HistogramBase::Sample value) {
union {
HistogramBase::Sample range;
unsigned char bytes[sizeof(HistogramBase::Sample)];
diff --git a/chromium/base/metrics/bucket_ranges.h b/chromium/base/metrics/bucket_ranges.h
index 1b6d069bdfa..476d2dfad43 100644
--- a/chromium/base/metrics/bucket_ranges.h
+++ b/chromium/base/metrics/bucket_ranges.h
@@ -99,6 +99,7 @@ class BASE_EXPORT BucketRanges {
//////////////////////////////////////////////////////////////////////////////
// Expose only for test.
BASE_EXPORT extern const uint32_t kCrcTable[256];
+uint32_t Crc32(uint32_t sum, HistogramBase::Sample value);
} // namespace base
diff --git a/chromium/base/metrics/field_trial.cc b/chromium/base/metrics/field_trial.cc
index ffb4744e7e7..f4835249944 100644
--- a/chromium/base/metrics/field_trial.cc
+++ b/chromium/base/metrics/field_trial.cc
@@ -26,7 +26,9 @@
#include "base/unguessable_token.h"
// On POSIX, the fd is shared using the mapping in GlobalDescriptors.
-#if defined(OS_POSIX) && !defined(OS_NACL)
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include "base/metrics/field_trial_memory_mac.h"
+#elif defined(OS_POSIX) && !defined(OS_NACL)
#include "base/posix/global_descriptors.h"
#endif
@@ -43,20 +45,6 @@ const char kPersistentStringSeparator = '/'; // Currently a slash.
// command line which forces its activation.
const char kActivationMarker = '*';
-// Use shared memory to communicate field trial (experiment) state. Set to false
-// for now while the implementation is fleshed out (e.g. data format, single
-// shared memory segment). See https://codereview.chromium.org/2365273004/ and
-// crbug.com/653874
-// The browser is the only process that has write access to the shared memory.
-// This is safe from race conditions because MakeIterable is a release operation
-// and GetNextOfType is an acquire operation, so memory writes before
-// MakeIterable happen before memory reads after GetNextOfType.
-#if defined(OS_FUCHSIA) // TODO(752368): Not yet supported on Fuchsia.
-const bool kUseSharedMemoryForFieldTrials = false;
-#else
-const bool kUseSharedMemoryForFieldTrials = true;
-#endif
-
// Constants for the field trial allocator.
const char kAllocatorName[] = "FieldTrialAllocator";
@@ -240,10 +228,10 @@ SharedMemoryHandle GetSharedMemoryReadOnlyHandle(SharedMemory* shared_memory) {
// writable mapping attempts, but the original one in |shm| survives
// and is still usable in the current process.
result.SetRegionReadOnly();
-#endif // OS_ANDROID
+#endif // defined(OS_ANDROID)
return result;
}
-#endif // !OS_NACL
+#endif // !defined(OS_NACL)
} // namespace
@@ -457,7 +445,7 @@ void FieldTrial::FinalizeGroupChoiceImpl(bool is_locked) {
SetGroupChoice(default_group_name_, kDefaultGroupNumber);
// Add the field trial to shared memory.
- if (kUseSharedMemoryForFieldTrials && trial_registered_)
+ if (trial_registered_)
FieldTrialList::OnGroupFinalized(is_locked, this);
}
@@ -829,7 +817,8 @@ void FieldTrialList::CreateTrialsFromCommandLine(
int fd_key) {
global_->create_trials_from_command_line_called_ = true;
-#if defined(OS_WIN) || defined(OS_FUCHSIA)
+#if defined(OS_WIN) || defined(OS_FUCHSIA) || \
+ (defined(OS_MACOSX) && !defined(OS_IOS))
if (cmd_line.HasSwitch(field_trial_handle_switch)) {
std::string switch_value =
cmd_line.GetSwitchValueASCII(field_trial_handle_switch);
@@ -869,8 +858,7 @@ void FieldTrialList::CreateFeaturesFromCommandLine(
const char* disable_features_switch,
FeatureList* feature_list) {
// Fallback to command line if not using shared memory.
- if (!kUseSharedMemoryForFieldTrials ||
- !global_->field_trial_allocator_.get()) {
+ if (!global_->field_trial_allocator_.get()) {
return feature_list->InitializeFromCommandLine(
command_line.GetSwitchValueASCII(enable_features_switch),
command_line.GetSwitchValueASCII(disable_features_switch));
@@ -886,18 +874,25 @@ void FieldTrialList::AppendFieldTrialHandleIfNeeded(
HandlesToInheritVector* handles) {
if (!global_)
return;
- if (kUseSharedMemoryForFieldTrials) {
- InstantiateFieldTrialAllocatorIfNeeded();
- if (global_->readonly_allocator_handle_.IsValid())
- handles->push_back(global_->readonly_allocator_handle_.GetHandle());
- }
+ InstantiateFieldTrialAllocatorIfNeeded();
+ if (global_->readonly_allocator_handle_.IsValid())
+ handles->push_back(global_->readonly_allocator_handle_.GetHandle());
}
#elif defined(OS_FUCHSIA)
// TODO(fuchsia): Implement shared-memory configuration (crbug.com/752368).
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+// static
+FieldTrialMemoryServer* FieldTrialList::GetFieldTrialMemoryServer() {
+ if (global_) {
+ InstantiateFieldTrialAllocatorIfNeeded();
+ return global_->field_trial_server_.get();
+ }
+ return nullptr;
+}
#elif defined(OS_POSIX) && !defined(OS_NACL)
// static
SharedMemoryHandle FieldTrialList::GetFieldTrialHandle() {
- if (global_ && kUseSharedMemoryForFieldTrials) {
+ if (global_) {
InstantiateFieldTrialAllocatorIfNeeded();
// We check for an invalid handle where this gets called.
return global_->readonly_allocator_handle_;
@@ -912,53 +907,37 @@ void FieldTrialList::CopyFieldTrialStateToFlags(
const char* enable_features_switch,
const char* disable_features_switch,
CommandLine* cmd_line) {
- // TODO(lawrencewu): Ideally, having the global would be guaranteed. However,
- // content browser tests currently don't create a FieldTrialList because they
- // don't run ChromeBrowserMainParts code where it's done for Chrome.
- // Some tests depend on the enable and disable features flag switch, though,
- // so we can still add those even though AllStatesToString() will be a no-op.
- if (!global_) {
+#if !defined(OS_FUCHSIA) // TODO(752368): Not yet supported on Fuchsia.
+ // Use shared memory to communicate field trial state to child processes.
+ // The browser is the only process that has write access to the shared memory.
+ InstantiateFieldTrialAllocatorIfNeeded();
+#endif // !defined(OS_FUCHSIA)
+
+ // If the readonly handle did not get created, fall back to flags.
+ if (!global_ || !global_->readonly_allocator_handle_.IsValid()) {
AddFeatureAndFieldTrialFlags(enable_features_switch,
disable_features_switch, cmd_line);
return;
}
- // Use shared memory to pass the state if the feature is enabled, otherwise
- // fallback to passing it via the command line as a string.
- if (kUseSharedMemoryForFieldTrials) {
- InstantiateFieldTrialAllocatorIfNeeded();
- // If the readonly handle didn't get duplicated properly, then fallback to
- // original behavior.
- if (!global_->readonly_allocator_handle_.IsValid()) {
- AddFeatureAndFieldTrialFlags(enable_features_switch,
- disable_features_switch, cmd_line);
- return;
- }
+ global_->field_trial_allocator_->UpdateTrackingHistograms();
+ std::string switch_value =
+ SerializeSharedMemoryHandleMetadata(global_->readonly_allocator_handle_);
+ cmd_line->AppendSwitchASCII(field_trial_handle_switch, switch_value);
- global_->field_trial_allocator_->UpdateTrackingHistograms();
- std::string switch_value = SerializeSharedMemoryHandleMetadata(
- global_->readonly_allocator_handle_);
- cmd_line->AppendSwitchASCII(field_trial_handle_switch, switch_value);
-
- // Append --enable-features and --disable-features switches corresponding
- // to the features enabled on the command-line, so that child and browser
- // process command lines match and clearly show what has been specified
- // explicitly by the user.
- std::string enabled_features;
- std::string disabled_features;
- FeatureList::GetInstance()->GetCommandLineFeatureOverrides(
- &enabled_features, &disabled_features);
-
- if (!enabled_features.empty())
- cmd_line->AppendSwitchASCII(enable_features_switch, enabled_features);
- if (!disabled_features.empty())
- cmd_line->AppendSwitchASCII(disable_features_switch, disabled_features);
-
- return;
- }
+ // Append --enable-features and --disable-features switches corresponding
+ // to the features enabled on the command-line, so that child and browser
+ // process command lines match and clearly show what has been specified
+ // explicitly by the user.
+ std::string enabled_features;
+ std::string disabled_features;
+ FeatureList::GetInstance()->GetCommandLineFeatureOverrides(
+ &enabled_features, &disabled_features);
- AddFeatureAndFieldTrialFlags(enable_features_switch, disable_features_switch,
- cmd_line);
+ if (!enabled_features.empty())
+ cmd_line->AppendSwitchASCII(enable_features_switch, enabled_features);
+ if (!disabled_features.empty())
+ cmd_line->AppendSwitchASCII(disable_features_switch, disabled_features);
}
// static
@@ -1042,8 +1021,7 @@ void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) {
if (!field_trial->enable_field_trial_)
return;
- if (kUseSharedMemoryForFieldTrials)
- ActivateFieldTrialEntryWhileLocked(field_trial);
+ ActivateFieldTrialEntryWhileLocked(field_trial);
}
// Recording for stability debugging has to be done inline as a task posted
@@ -1215,6 +1193,10 @@ std::string FieldTrialList::SerializeSharedMemoryHandleMetadata(
ss << uintptr_handle << ",";
#elif defined(OS_FUCHSIA)
ss << shm.GetHandle() << ",";
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+ // The handle on Mac is looked up directly by the child, rather than being
+ // transferred to the child over the command line.
+ ss << "0,";
#elif !defined(OS_POSIX)
#error Unsupported OS
#endif
@@ -1225,7 +1207,8 @@ std::string FieldTrialList::SerializeSharedMemoryHandleMetadata(
return ss.str();
}
-#if defined(OS_WIN) || defined(OS_FUCHSIA)
+#if defined(OS_WIN) || defined(OS_FUCHSIA) || \
+ (defined(OS_MACOSX) && !defined(OS_IOS))
// static
SharedMemoryHandle FieldTrialList::DeserializeSharedMemoryHandleMetadata(
@@ -1252,7 +1235,12 @@ SharedMemoryHandle FieldTrialList::DeserializeSharedMemoryHandleMetadata(
FALSE, DUPLICATE_SAME_ACCESS);
CloseHandle(parent_handle);
}
-#endif // defined(OS_WIN)
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+ mac::ScopedMachSendRight scoped_handle =
+ FieldTrialMemoryClient::AcquireMemoryObject();
+ if (scoped_handle == MACH_PORT_NULL)
+ return SharedMemoryHandle();
+#endif
base::UnguessableToken guid;
if (!DeserializeGUIDFromStringPieces(tokens[1], tokens[2], &guid))
@@ -1262,6 +1250,11 @@ SharedMemoryHandle FieldTrialList::DeserializeSharedMemoryHandleMetadata(
if (!base::StringToInt(tokens[3], &size))
return SharedMemoryHandle();
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ // Transfer ownership to SharedMemoryHandle.
+ mach_port_t handle = scoped_handle.release();
+#endif
+
return SharedMemoryHandle(handle, static_cast<size_t>(size), guid);
}
@@ -1291,7 +1284,8 @@ SharedMemoryHandle FieldTrialList::DeserializeSharedMemoryHandleMetadata(
#endif
-#if defined(OS_WIN) || defined(OS_FUCHSIA)
+#if defined(OS_WIN) || defined(OS_FUCHSIA) || \
+ (defined(OS_MACOSX) && !defined(OS_IOS))
// static
bool FieldTrialList::CreateTrialsFromSwitchValue(
const std::string& switch_value) {
@@ -1305,9 +1299,6 @@ bool FieldTrialList::CreateTrialsFromSwitchValue(
bool FieldTrialList::CreateTrialsFromDescriptor(
int fd_key,
const std::string& switch_value) {
- if (!kUseSharedMemoryForFieldTrials)
- return false;
-
if (fd_key == -1)
return false;
@@ -1374,6 +1365,7 @@ bool FieldTrialList::CreateTrialsFromSharedMemory(
void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() {
if (!global_)
return;
+
AutoLock auto_lock(global_->lock_);
// Create the allocator if not already created and add all existing trials.
if (global_->field_trial_allocator_ != nullptr)
@@ -1382,9 +1374,6 @@ void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() {
SharedMemoryCreateOptions options;
options.size = kFieldTrialAllocationSize;
options.share_read_only = true;
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- options.type = SharedMemoryHandle::POSIX;
-#endif
std::unique_ptr<SharedMemory> shm(new SharedMemory());
if (!shm->Create(options))
@@ -1411,6 +1400,13 @@ void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() {
global_->readonly_allocator_handle_ = GetSharedMemoryReadOnlyHandle(
global_->field_trial_allocator_->shared_memory());
#endif
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ global_->field_trial_server_ = std::make_unique<FieldTrialMemoryServer>(
+ global_->readonly_allocator_handle_.GetMemoryObject());
+ bool ok = global_->field_trial_server_->Start();
+ DCHECK(ok);
+#endif
}
// static
diff --git a/chromium/base/metrics/field_trial.h b/chromium/base/metrics/field_trial.h
index d439fccee95..95f646fe2eb 100644
--- a/chromium/base/metrics/field_trial.h
+++ b/chromium/base/metrics/field_trial.h
@@ -85,6 +85,7 @@
namespace base {
class FieldTrialList;
+class FieldTrialMemoryServer;
class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
public:
@@ -588,6 +589,10 @@ class BASE_EXPORT FieldTrialList {
base::HandlesToInheritVector* handles);
#elif defined(OS_FUCHSIA)
// TODO(fuchsia): Implement shared-memory configuration (crbug.com/752368).
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+ // On Mac, the field trial shared memory is accessed via a Mach server, which
+ // the child looks up directly.
+ static FieldTrialMemoryServer* GetFieldTrialMemoryServer();
#elif defined(OS_POSIX) && !defined(OS_NACL)
// On POSIX, we also need to explicitly pass down this file descriptor that
// should be shared with the child process. Returns an invalid handle if it
@@ -682,6 +687,7 @@ class BASE_EXPORT FieldTrialList {
FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, ClearParamsFromSharedMemory);
FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest,
SerializeSharedMemoryHandleMetadata);
+ friend int SerializeSharedMemoryHandleMetadata(void);
FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, CheckReadOnlySharedMemoryHandle);
// Serialization is used to pass information about the handle to child
@@ -690,7 +696,8 @@ class BASE_EXPORT FieldTrialList {
// underlying OS resource - that must be done by the Process launcher.
static std::string SerializeSharedMemoryHandleMetadata(
const SharedMemoryHandle& shm);
-#if defined(OS_WIN) || defined(OS_FUCHSIA)
+#if defined(OS_WIN) || defined(OS_FUCHSIA) || \
+ (defined(OS_MACOSX) && !defined(OS_IOS))
static SharedMemoryHandle DeserializeSharedMemoryHandleMetadata(
const std::string& switch_value);
#elif defined(OS_POSIX) && !defined(OS_NACL)
@@ -699,7 +706,8 @@ class BASE_EXPORT FieldTrialList {
const std::string& switch_value);
#endif
-#if defined(OS_WIN) || defined(OS_FUCHSIA)
+#if defined(OS_WIN) || defined(OS_FUCHSIA) || \
+ (defined(OS_MACOSX) && !defined(OS_IOS))
// Takes in |handle_switch| from the command line which represents the shared
// memory handle for field trials, parses it, and creates the field trials.
// Returns true on success, false on failure.
@@ -793,6 +801,12 @@ class BASE_EXPORT FieldTrialList {
// AppendFieldTrialHandleIfNeeded().
base::SharedMemoryHandle readonly_allocator_handle_;
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ // Mach message server that handles requests to acquire the shared memory
+ // object.
+ std::unique_ptr<FieldTrialMemoryServer> field_trial_server_;
+#endif
+
// Tracks whether CreateTrialsFromCommandLine() has been called.
bool create_trials_from_command_line_called_ = false;
diff --git a/chromium/base/metrics/field_trial_memory_mac.cc b/chromium/base/metrics/field_trial_memory_mac.cc
new file mode 100644
index 00000000000..be1adb2e664
--- /dev/null
+++ b/chromium/base/metrics/field_trial_memory_mac.cc
@@ -0,0 +1,206 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/field_trial_memory_mac.h"
+
+#include <bsm/libbsm.h>
+#include <libproc.h>
+#include <mach/mig.h>
+#include <servers/bootstrap.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mach_logging.h"
+#include "base/mac/scoped_mach_msg_destroy.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+
+namespace {
+
+// The name to use in the bootstrap server, formatted with the BaseBundleID and
+// PID of the server.
+const char kBootstrapNameFormat[] = "%s.FieldTrialMemoryServer.%d";
+
+enum FieldTrialMsgId : mach_msg_id_t {
+ kFieldTrialMsgIdRequest = 'FTrq',
+ kFieldTrialMsgIdResponse = 'FTsp',
+};
+
+// Message received by the server for handling lookup lookup requests.
+struct FieldTrialMemoryRequestMessage : public mach_msg_base_t {
+ // The size of the message excluding the trailer, used for msgh_size.
+ static const mach_msg_size_t kSendSize;
+
+ mach_msg_audit_trailer_t trailer;
+};
+
+const mach_msg_size_t FieldTrialMemoryRequestMessage::kSendSize =
+ sizeof(FieldTrialMemoryRequestMessage) - sizeof(trailer);
+
+// Message used for sending and receiving the memory object handle.
+struct FieldTrialMemoryResponseMessage : public mach_msg_base_t {
+ // The size of the message excluding the trailer, used for msgh_size.
+ static const mach_msg_size_t kSendSize;
+
+ mach_msg_port_descriptor_t port;
+ mach_msg_trailer_t trailer;
+};
+
+const mach_msg_size_t FieldTrialMemoryResponseMessage::kSendSize =
+ sizeof(FieldTrialMemoryResponseMessage) - sizeof(trailer);
+
+} // namespace
+
+FieldTrialMemoryServer::FieldTrialMemoryServer(mach_port_t memory_object)
+ : memory_object_(memory_object), server_pid_(getpid()) {
+ DCHECK(memory_object != MACH_PORT_NULL);
+}
+
+FieldTrialMemoryServer::~FieldTrialMemoryServer() {}
+
+bool FieldTrialMemoryServer::Start() {
+ std::string bootstrap_name = GetBootstrapName();
+ kern_return_t kr = bootstrap_check_in(
+ bootstrap_port, bootstrap_name.c_str(),
+ mac::ScopedMachReceiveRight::Receiver(server_port_).get());
+ if (kr != KERN_SUCCESS) {
+ BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_check_in " << bootstrap_name;
+ return false;
+ }
+
+ dispatch_source_ = std::make_unique<DispatchSourceMach>(
+ "org.chromium.base.FieldTrialMemoryServer", server_port_.get(), ^{
+ HandleRequest();
+ });
+ dispatch_source_->Resume();
+ return true;
+}
+
+// static
+std::string FieldTrialMemoryServer::GetBootstrapName() {
+ return StringPrintf(kBootstrapNameFormat, mac::BaseBundleID(), getpid());
+}
+
+void FieldTrialMemoryServer::HandleRequest() {
+ // Receive the request message, using the kernel audit token to ascertain the
+ // PID of the sender.
+ FieldTrialMemoryRequestMessage request{};
+ request.header.msgh_size = sizeof(request);
+ request.header.msgh_local_port = server_port_.get();
+
+ const mach_msg_option_t options =
+ MACH_RCV_MSG | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
+ MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT);
+
+ kern_return_t kr =
+ mach_msg(&request.header, options, 0, sizeof(request), server_port_.get(),
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ if (kr != KERN_SUCCESS) {
+ MACH_LOG(ERROR, kr) << "mach_msg receive";
+ return;
+ }
+
+ // Destroy the message in case of an early return, which will release
+ // any rights from a bad message. In the case of a disallowed sender,
+ // the destruction of the reply port will break them out of a mach_msg.
+ ScopedMachMsgDestroy scoped_message(&request.header);
+
+ if (request.header.msgh_id != kFieldTrialMsgIdRequest ||
+ request.header.msgh_size != request.kSendSize) {
+ // Do not reply to messages that are unexpected.
+ return;
+ }
+
+ // A client is allowed to look up the object if the sending process is a
+ // direct child of this server's process.
+ pid_t sender_pid = audit_token_to_pid(request.trailer.msgh_audit);
+ proc_bsdshortinfo sender{};
+ int rv = proc_pidinfo(sender_pid, PROC_PIDT_SHORTBSDINFO, 0, &sender,
+ PROC_PIDT_SHORTBSDINFO_SIZE);
+ if (rv != PROC_PIDT_SHORTBSDINFO_SIZE ||
+ sender.pbsi_ppid != static_cast<uint32_t>(server_pid_)) {
+ return;
+ }
+
+ FieldTrialMemoryResponseMessage response{};
+ response.header.msgh_bits =
+ MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND_ONCE) |
+ MACH_MSGH_BITS_COMPLEX;
+ response.header.msgh_size = response.kSendSize;
+ response.header.msgh_remote_port = request.header.msgh_remote_port;
+ response.header.msgh_id = kFieldTrialMsgIdResponse;
+ response.body.msgh_descriptor_count = 1;
+ response.port.name = memory_object_;
+ response.port.disposition = MACH_MSG_TYPE_COPY_SEND;
+ response.port.type = MACH_MSG_PORT_DESCRIPTOR;
+
+ scoped_message.Disarm();
+
+ kr = mach_msg(&response.header, MACH_SEND_MSG, response.header.msgh_size, 0,
+ MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr) << "mach_msg send";
+}
+
+// static
+mac::ScopedMachSendRight FieldTrialMemoryClient::AcquireMemoryObject() {
+ mac::ScopedMachSendRight server_port;
+ std::string bootstrap_name = GetBootstrapName();
+ kern_return_t kr = bootstrap_look_up(
+ bootstrap_port, const_cast<char*>(bootstrap_name.c_str()),
+ mac::ScopedMachSendRight::Receiver(server_port).get());
+ if (kr != KERN_SUCCESS) {
+ BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_look_up " << bootstrap_name;
+ return mac::ScopedMachSendRight();
+ }
+
+ return ChildSendRequest(std::move(server_port));
+}
+
+// static
+std::string FieldTrialMemoryClient::GetBootstrapName() {
+ return StringPrintf(kBootstrapNameFormat, mac::BaseBundleID(), getppid());
+}
+
+// static
+mac::ScopedMachSendRight FieldTrialMemoryClient::ChildSendRequest(
+ mac::ScopedMachSendRight server_port) {
+ // Perform a send and receive mach_msg.
+ union {
+ FieldTrialMemoryRequestMessage request;
+ FieldTrialMemoryResponseMessage response;
+ } msg{};
+ msg.request.header.msgh_bits =
+ MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+ // The size of |msg| is used for receiving since it includes space for the
+ // trailer, but for the request being sent, the size is just the base message.
+ msg.request.header.msgh_size = msg.request.kSendSize;
+ msg.request.header.msgh_remote_port = server_port.release();
+ msg.request.header.msgh_local_port = mig_get_reply_port();
+ msg.request.header.msgh_id = kFieldTrialMsgIdRequest;
+
+ kern_return_t kr =
+ mach_msg(&msg.request.header, MACH_SEND_MSG | MACH_RCV_MSG,
+ msg.request.header.msgh_size, sizeof(msg.response),
+ msg.request.header.msgh_local_port, MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ if (kr != KERN_SUCCESS) {
+ MACH_LOG(ERROR, kr) << "mach_msg";
+ return mac::ScopedMachSendRight();
+ }
+
+ if (msg.response.header.msgh_id != kFieldTrialMsgIdResponse ||
+ msg.response.header.msgh_size != msg.response.kSendSize) {
+ return mac::ScopedMachSendRight();
+ }
+
+ return mac::ScopedMachSendRight(msg.response.port.name);
+}
+
+FieldTrialMemoryClient::FieldTrialMemoryClient() = default;
+
+FieldTrialMemoryClient::~FieldTrialMemoryClient() = default;
+
+} // namespace base
diff --git a/chromium/base/metrics/field_trial_memory_mac.h b/chromium/base/metrics/field_trial_memory_mac.h
new file mode 100644
index 00000000000..3a323760216
--- /dev/null
+++ b/chromium/base/metrics/field_trial_memory_mac.h
@@ -0,0 +1,85 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_METRICS_FIELD_TRIAL_MEMORY_MAC_H_
+#define BASE_METRICS_FIELD_TRIAL_MEMORY_MAC_H_
+
+#include <mach/port.h>
+#include <sys/types.h>
+
+#include <memory>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/mac/dispatch_source_mach.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/macros.h"
+
+namespace base {
+
+// FieldTrialMemoryServer services requests for the FieldTrial shared memory
+// region on Mac. Shared memory on Mac uses Mach ports, which cannot be
+// transferred across process creation. Instead, this class publishes an
+// endpoint in the bootstrap server. Child processes look up the server and then
+// send requests to acquire the shared memory object. Only processes that are
+// direct children of the process that is running this server are allowed to
+// acquire the memory object send right.
+class BASE_EXPORT FieldTrialMemoryServer {
+ public:
+ // Creates a server that will vend access to the passed |memory_object|.
+ // This does not change the user refcount of the object. Start() must be
+ // called before requests will be processed.
+ explicit FieldTrialMemoryServer(mach_port_t memory_object);
+ ~FieldTrialMemoryServer();
+
+ // Starts processing requests for the server. Returns false if the server
+ // could not be started and true on success.
+ bool Start();
+
+ private:
+ friend class FieldTrialMemoryServerTest;
+
+ // Exposed for testing.
+ void set_server_pid(pid_t pid) { server_pid_ = pid; }
+
+ // Returns the name of the server to publish in the bootstrap namespace.
+ static std::string GetBootstrapName();
+
+ // The server-side Mach message handler.
+ void HandleRequest();
+
+ mach_port_t memory_object_; // weak
+ pid_t server_pid_; // PPID used for access control checks.
+ mac::ScopedMachReceiveRight server_port_;
+ std::unique_ptr<DispatchSourceMach> dispatch_source_;
+
+ DISALLOW_COPY_AND_ASSIGN(FieldTrialMemoryServer);
+};
+
+// Client class for accessing the memory object exposed by the
+// FieldTrialMemoryServer.
+class BASE_EXPORT FieldTrialMemoryClient {
+ public:
+ // Called by children of the process running the FieldTrialMemoryServer, this
+ // attempts to acquire the port for the |memory_object_|. Returns the port
+ // on success or MACH_PORT_NULL on error or failure.
+ static mac::ScopedMachSendRight AcquireMemoryObject();
+
+ // Returns the name of the server to look up in the bootstrap namespace.
+ static std::string GetBootstrapName();
+
+ private:
+ // Sends the Mach message to |server_port| to acquire the memory object.
+ static mac::ScopedMachSendRight ChildSendRequest(
+ mac::ScopedMachSendRight server_port);
+
+ FieldTrialMemoryClient();
+ ~FieldTrialMemoryClient();
+
+ DISALLOW_COPY_AND_ASSIGN(FieldTrialMemoryClient);
+};
+
+} // namespace base
+
+#endif // BASE_METRICS_FIELD_TRIAL_MEMORY_MAC_H_
diff --git a/chromium/base/metrics/field_trial_memory_mac_unittest.cc b/chromium/base/metrics/field_trial_memory_mac_unittest.cc
new file mode 100644
index 00000000000..536aa3a232f
--- /dev/null
+++ b/chromium/base/metrics/field_trial_memory_mac_unittest.cc
@@ -0,0 +1,118 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/field_trial_memory_mac.h"
+
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+
+#include "base/mac/mach_logging.h"
+#include "base/mac/scoped_mach_vm.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace base {
+
+namespace {
+
+enum ChildExitCode {
+ kChildExitInvalid,
+ kChildExitNoPort,
+ kChildExitMapFailed,
+ kChildExitBadPattern,
+ kChildExitSuccess,
+};
+
+constexpr char kMemoryTestPattern[] = "Hello there, bear";
+
+constexpr mach_vm_size_t kMemoryAllocationSize = 1024;
+
+} // namespace
+
+class FieldTrialMemoryServerTest : public MultiProcessTest {
+ public:
+ void SetUp() override {
+ mach_vm_address_t address = 0;
+ mach_vm_size_t size = mach_vm_round_page(kMemoryAllocationSize);
+ kern_return_t kr =
+ mach_vm_allocate(mach_task_self(), &address, size, VM_FLAGS_ANYWHERE);
+ ASSERT_EQ(kr, KERN_SUCCESS) << "mach_vm_allocate";
+ memory_.reset(address, size);
+
+ kr = mach_make_memory_entry_64(
+ mach_task_self(), &size, address, VM_PROT_READ,
+ mac::ScopedMachSendRight::Receiver(memory_object_).get(),
+ MACH_PORT_NULL);
+ ASSERT_EQ(kr, KERN_SUCCESS) << "mach_make_memory_entry_64";
+
+ memcpy(reinterpret_cast<void*>(address), kMemoryTestPattern,
+ sizeof(kMemoryTestPattern));
+ }
+
+ void SetServerPid(FieldTrialMemoryServer* server, pid_t server_pid) {
+ server->set_server_pid(server_pid);
+ }
+
+ mach_port_t memory_object() { return memory_object_.get(); }
+
+ private:
+ mac::ScopedMachVM memory_;
+ mac::ScopedMachSendRight memory_object_;
+};
+
+MULTIPROCESS_TEST_MAIN(AcquireMemoryObjectAndMap) {
+ mac::ScopedMachSendRight memory_object =
+ FieldTrialMemoryClient::AcquireMemoryObject();
+ if (memory_object == MACH_PORT_NULL)
+ return kChildExitNoPort;
+
+ mach_vm_address_t address = 0;
+ kern_return_t kr =
+ mach_vm_map(mach_task_self(), &address, kMemoryAllocationSize, 0,
+ VM_FLAGS_ANYWHERE, memory_object.get(), 0, false,
+ VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE);
+ if (kr != KERN_SUCCESS) {
+ MACH_LOG(ERROR, kr) << "mach_vm_map";
+ return kChildExitMapFailed;
+ }
+
+ if (memcmp(kMemoryTestPattern, reinterpret_cast<void*>(address),
+ sizeof(kMemoryTestPattern)) != 0) {
+ return kChildExitBadPattern;
+ }
+
+ return kChildExitSuccess;
+}
+
+TEST_F(FieldTrialMemoryServerTest, AllowedPid) {
+ FieldTrialMemoryServer server(memory_object());
+ ASSERT_TRUE(server.Start());
+
+ Process child = SpawnChild("AcquireMemoryObjectAndMap");
+
+ int exit_code;
+ ASSERT_TRUE(WaitForMultiprocessTestChildExit(
+ child, TestTimeouts::action_timeout(), &exit_code));
+
+ EXPECT_EQ(kChildExitSuccess, exit_code);
+}
+
+TEST_F(FieldTrialMemoryServerTest, BlockedPid) {
+ FieldTrialMemoryServer server(memory_object());
+ // Override the server's PID so that the request does not look like it is
+ // coming from a process that is the child of the server.
+ SetServerPid(&server, 1);
+ ASSERT_TRUE(server.Start());
+
+ Process child = SpawnChild("AcquireMemoryObjectAndMap");
+
+ int exit_code;
+ ASSERT_TRUE(WaitForMultiprocessTestChildExit(
+ child, TestTimeouts::action_timeout(), &exit_code));
+
+ EXPECT_EQ(kChildExitNoPort, exit_code);
+}
+
+} // namespace base
diff --git a/chromium/base/metrics/field_trial_unittest.cc b/chromium/base/metrics/field_trial_unittest.cc
index 7dbe737d8a8..dce2dd6d817 100644
--- a/chromium/base/metrics/field_trial_unittest.cc
+++ b/chromium/base/metrics/field_trial_unittest.cc
@@ -11,7 +11,6 @@
#include "base/feature_list.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
#include "base/metrics/field_trial_param_associator.h"
#include "base/rand_util.h"
#include "base/run_loop.h"
@@ -19,10 +18,18 @@
#include "base/strings/stringprintf.h"
#include "base/test/gtest_util.h"
#include "base/test/mock_entropy_provider.h"
+#include "base/test/multiprocess_test.h"
#include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_task_environment.h"
#include "base/test/test_shared_memory_util.h"
+#include "base/test/test_timeouts.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include "base/metrics/field_trial_memory_mac.h"
+#endif
namespace base {
@@ -100,7 +107,7 @@ class FieldTrialTest : public ::testing::Test {
FieldTrialTest() : trial_list_(nullptr) {}
private:
- MessageLoop message_loop_;
+ test::ScopedTaskEnvironment scoped_task_environment_;
FieldTrialList trial_list_;
DISALLOW_COPY_AND_ASSIGN(FieldTrialTest);
@@ -1426,33 +1433,66 @@ TEST(FieldTrialListTest, DumpAndFetchFromSharedMemory) {
EXPECT_EQ("value2", shm_params["key2"]);
}
-#if !defined(OS_NACL)
-TEST(FieldTrialListTest, SerializeSharedMemoryHandleMetadata) {
- std::unique_ptr<SharedMemory> shm(new SharedMemory());
- shm->CreateAndMapAnonymous(4 << 10);
-
+#if !defined(OS_NACL) && !defined(OS_IOS)
+MULTIPROCESS_TEST_MAIN(SerializeSharedMemoryHandleMetadata) {
std::string serialized =
- FieldTrialList::SerializeSharedMemoryHandleMetadata(shm->handle());
-#if defined(OS_WIN) || defined(OS_FUCHSIA)
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII("field_trials");
+ std::string guid_string =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII("guid");
+
+#if defined(OS_WIN) || defined(OS_FUCHSIA) || \
+ (defined(OS_MACOSX) && !defined(OS_IOS))
SharedMemoryHandle deserialized =
FieldTrialList::DeserializeSharedMemoryHandleMetadata(serialized);
#else
- // Use a valid-looking arbitrary number for the file descriptor. It's not
- // being used in this unittest, but needs to pass sanity checks in the
- // handle's constructor.
+ // Use the arbitrary value selected below.
SharedMemoryHandle deserialized =
FieldTrialList::DeserializeSharedMemoryHandleMetadata(42, serialized);
#endif
- EXPECT_EQ(deserialized.GetGUID(), shm->handle().GetGUID());
- EXPECT_FALSE(deserialized.GetGUID().is_empty());
+ CHECK_EQ(deserialized.GetGUID().ToString(), guid_string);
+ CHECK(!deserialized.GetGUID().is_empty());
+
+ return 0;
+}
+
+TEST(FieldTrialListTest, SerializeSharedMemoryHandleMetadata) {
+ std::unique_ptr<SharedMemory> shm(new SharedMemory());
+ shm->CreateAndMapAnonymous(4 << 10);
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ FieldTrialMemoryServer mach_server(shm->handle().GetMemoryObject());
+ ASSERT_TRUE(mach_server.Start());
+#endif
+
+ std::string serialized =
+ FieldTrialList::SerializeSharedMemoryHandleMetadata(shm->handle());
+
+ LaunchOptions options;
+#if defined(OS_POSIX) && (!defined(OS_MACOSX) && !defined(OS_IOS))
+ // Pick an arbitrary FD number to use for the shmem FD in the child.
+ options.fds_to_remap.emplace_back(
+ std::make_pair(shm->handle().GetHandle(), 42));
+#endif
+ CommandLine cmd_line = GetMultiProcessTestChildBaseCommandLine();
+ cmd_line.AppendSwitchASCII("field_trials", serialized);
+ cmd_line.AppendSwitchASCII("guid", shm->handle().GetGUID().ToString());
+
+ Process process = SpawnMultiProcessTestChild(
+ "SerializeSharedMemoryHandleMetadata", cmd_line, options);
+
+ int exit_code;
+ EXPECT_TRUE(WaitForMultiprocessTestChildExit(
+ process, TestTimeouts::action_timeout(), &exit_code));
+ EXPECT_EQ(0, exit_code);
}
#endif // !defined(OS_NACL)
// Verify that the field trial shared memory handle is really read-only, and
-// does not allow writable mappings. Test disabled on NaCl, Windows and Fuchsia
-// which don't support/implement GetFieldTrialHandle(). For Fuchsia, see
-// crbug.com/752368
-#if !defined(OS_NACL) && !defined(OS_WIN) && !defined(OS_FUCHSIA)
+// does not allow writable mappings. Test disabled on NaCl, Windows, Fuchsia,
+// and Mac, which don't support/implement GetFieldTrialHandle(). For Fuchsia,
+// see crbug.com/752368
+#if !defined(OS_NACL) && !defined(OS_WIN) && !defined(OS_FUCHSIA) && \
+ (!defined(OS_MACOSX) && !defined(OS_IOS))
TEST(FieldTrialListTest, CheckReadOnlySharedMemoryHandle) {
FieldTrialList field_trial_list(nullptr);
FieldTrialList::CreateFieldTrial("Trial1", "Group1");
diff --git a/chromium/base/metrics/histogram.cc b/chromium/base/metrics/histogram.cc
index 1b80abbd6bd..0dc4bbfe707 100644
--- a/chromium/base/metrics/histogram.cc
+++ b/chromium/base/metrics/histogram.cc
@@ -93,7 +93,7 @@ typedef HistogramBase::Count Count;
typedef HistogramBase::Sample Sample;
// static
-const uint32_t Histogram::kBucketCount_MAX = 16384u;
+const uint32_t Histogram::kBucketCount_MAX = 10002u;
class Histogram::Factory {
public:
@@ -341,6 +341,7 @@ void Histogram::InitializeBucketRanges(Sample minimum,
while (bucket_count > ++bucket_index) {
double log_current;
log_current = log(static_cast<double>(current));
+ debug::Alias(&log_current);
// Calculate the count'th root of the range.
log_ratio = (log_max - log_current) / (bucket_count - bucket_index);
// See where the next bucket would start.
@@ -421,27 +422,37 @@ bool Histogram::InspectConstructionArguments(StringPiece name,
Sample* minimum,
Sample* maximum,
uint32_t* bucket_count) {
+ bool check_okay = true;
+
+ // Checks below must be done after any min/max swap.
+ if (*minimum > *maximum) {
+ check_okay = false;
+ std::swap(*minimum, *maximum);
+ }
+
// Defensive code for backward compatibility.
if (*minimum < 1) {
DVLOG(1) << "Histogram: " << name << " has bad minimum: " << *minimum;
*minimum = 1;
+ if (*maximum < 1)
+ *maximum = 1;
}
if (*maximum >= kSampleType_MAX) {
DVLOG(1) << "Histogram: " << name << " has bad maximum: " << *maximum;
*maximum = kSampleType_MAX - 1;
}
if (*bucket_count >= kBucketCount_MAX) {
+ check_okay = false;
DVLOG(1) << "Histogram: " << name << " has bad bucket_count: "
<< *bucket_count;
*bucket_count = kBucketCount_MAX - 1;
}
-
- bool check_okay = true;
-
- if (*minimum > *maximum) {
- check_okay = false;
- std::swap(*minimum, *maximum);
+ if (*bucket_count > 1002) {
+ UmaHistogramSparse("Histogram.TooManyBuckets.1000",
+ static_cast<Sample>(HashMetricName(name)));
}
+
+ // Ensure parameters are sane.
if (*maximum == *minimum) {
check_okay = false;
*maximum = *minimum + 1;
@@ -450,13 +461,6 @@ bool Histogram::InspectConstructionArguments(StringPiece name,
check_okay = false;
*bucket_count = 3;
}
- // Very high bucket counts are wasteful. Use a sparse histogram instead.
- // Value of 10002 equals a user-supplied value of 10k + 2 overflow buckets.
- constexpr uint32_t kMaxBucketCount = 10002;
- if (*bucket_count > kMaxBucketCount) {
- check_okay = false;
- *bucket_count = kMaxBucketCount;
- }
if (*bucket_count > static_cast<uint32_t>(*maximum - *minimum + 2)) {
check_okay = false;
*bucket_count = static_cast<uint32_t>(*maximum - *minimum + 2);
@@ -921,6 +925,18 @@ HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
uint32_t bucket_count,
int32_t flags,
const DescriptionPair descriptions[]) {
+ // Originally, histograms were required to have at least one sample value
+ // plus underflow and overflow buckets. For single-entry enumerations,
+ // that one value is usually zero (which IS the underflow bucket)
+ // resulting in a |maximum| value of 1 (the exclusive upper-bound) and only
+ // the two outlier buckets. Handle this by making max==2 and buckets==3.
+ // This usually won't have any cost since the single-value-optimization
+ // will be used until the count exceeds 16 bits.
+ if (maximum == 1 && bucket_count == 2) {
+ maximum = 2;
+ bucket_count = 3;
+ }
+
bool valid_arguments = Histogram::InspectConstructionArguments(
name, &minimum, &maximum, &bucket_count);
DCHECK(valid_arguments);
diff --git a/chromium/base/metrics/histogram_flattener.h b/chromium/base/metrics/histogram_flattener.h
index 6a5e3f42988..ed81154364b 100644
--- a/chromium/base/metrics/histogram_flattener.h
+++ b/chromium/base/metrics/histogram_flattener.h
@@ -19,12 +19,13 @@ class HistogramSamples;
// handles the logistics of gathering up available histograms for recording.
class BASE_EXPORT HistogramFlattener {
public:
+ virtual ~HistogramFlattener() = default;
+
virtual void RecordDelta(const HistogramBase& histogram,
const HistogramSamples& snapshot) = 0;
protected:
HistogramFlattener() = default;
- virtual ~HistogramFlattener() = default;
private:
DISALLOW_COPY_AND_ASSIGN(HistogramFlattener);
diff --git a/chromium/base/metrics/histogram_functions.cc b/chromium/base/metrics/histogram_functions.cc
index 31bf219e5af..e0d7b2ddfcf 100644
--- a/chromium/base/metrics/histogram_functions.cc
+++ b/chromium/base/metrics/histogram_functions.cc
@@ -89,6 +89,22 @@ void UmaHistogramLongTimes(const std::string& name, TimeDelta sample) {
TimeDelta::FromHours(1), 50);
}
+void UmaHistogramCustomMicrosecondsTimes(const std::string& name,
+ TimeDelta sample,
+ TimeDelta min,
+ TimeDelta max,
+ int buckets) {
+ HistogramBase* histogram = Histogram::FactoryTimeGet(
+ name, min, max, buckets, HistogramBase::kUmaTargetedHistogramFlag);
+ histogram->AddTimeMicrosecondsGranularity(sample);
+}
+
+void UmaHistogramMicrosecondsTimes(const std::string& name, TimeDelta sample) {
+ UmaHistogramCustomMicrosecondsTimes(name, sample,
+ TimeDelta::FromMicroseconds(1),
+ TimeDelta::FromSeconds(10), 50);
+}
+
void UmaHistogramMemoryKB(const std::string& name, int sample) {
UmaHistogramCustomCounts(name, sample, 1000, 500000, 50);
}
diff --git a/chromium/base/metrics/histogram_functions.h b/chromium/base/metrics/histogram_functions.h
index 60c005726f5..3d95464f555 100644
--- a/chromium/base/metrics/histogram_functions.h
+++ b/chromium/base/metrics/histogram_functions.h
@@ -101,7 +101,7 @@ BASE_EXPORT void UmaHistogramCounts100000(const std::string& name, int sample);
BASE_EXPORT void UmaHistogramCounts1M(const std::string& name, int sample);
BASE_EXPORT void UmaHistogramCounts10M(const std::string& name, int sample);
-// For histograms storing times.
+// For histograms storing times. It uses milliseconds granularity.
BASE_EXPORT void UmaHistogramCustomTimes(const std::string& name,
TimeDelta sample,
TimeDelta min,
@@ -116,6 +116,17 @@ BASE_EXPORT void UmaHistogramMediumTimes(const std::string& name,
BASE_EXPORT void UmaHistogramLongTimes(const std::string& name,
TimeDelta sample);
+// For histograms storing times with microseconds granularity.
+BASE_EXPORT void UmaHistogramCustomMicrosecondsTimes(const std::string& name,
+ TimeDelta sample,
+ TimeDelta min,
+ TimeDelta max,
+ int buckets);
+
+// For microseconds timings from 1 microsecond up to 10 seconds (50 buckets).
+BASE_EXPORT void UmaHistogramMicrosecondsTimes(const std::string& name,
+ TimeDelta sample);
+
// For recording memory related histograms.
// Used to measure common KB-granularity memory stats. Range is up to 500M.
BASE_EXPORT void UmaHistogramMemoryKB(const std::string& name, int sample);
diff --git a/chromium/base/metrics/histogram_macros.h b/chromium/base/metrics/histogram_macros.h
index 93bd4bdff7c..892f1a6cba2 100644
--- a/chromium/base/metrics/histogram_macros.h
+++ b/chromium/base/metrics/histogram_macros.h
@@ -43,8 +43,9 @@
// having to handle a sentinel no-op value.
//
// Sample usage:
-// // These values are persisted to logs. Entries should not be renumbered and
-// // numeric values should never be reused.
+// // These values are logged to UMA. Entries should not be renumbered and
+// // numeric values should never be reused. Please keep in sync with "MyEnum"
+// // in src/tools/metrics/histograms/enums.xml.
// enum class MyEnum {
// kFirstValue = 0,
// kSecondValue = 1,
@@ -59,8 +60,9 @@
// greater than any other enumerator that will be sampled.
//
// Sample usage:
-// // These values are persisted to logs. Entries should not be renumbered and
-// // numeric values should never be reused.
+// // These values are logged to UMA. Entries should not be renumbered and
+// // numeric values should never be reused. Please keep in sync with "MyEnum"
+// // in src/tools/metrics/histograms/enums.xml.
// enum class MyEnum {
// FIRST_VALUE = 0,
// SECOND_VALUE = 1,
@@ -77,10 +79,10 @@
// enum to an arithmetic type and adding one. Instead, prefer the two argument
// version of the macro which automatically deduces the boundary from kMaxValue.
#define UMA_HISTOGRAM_ENUMERATION(name, ...) \
- CR_EXPAND_ARG(INTERNAL_UMA_HISTOGRAM_ENUMERATION_GET_MACRO( \
+ INTERNAL_UMA_HISTOGRAM_ENUMERATION_GET_MACRO( \
__VA_ARGS__, INTERNAL_UMA_HISTOGRAM_ENUMERATION_SPECIFY_BOUNDARY, \
- INTERNAL_UMA_HISTOGRAM_ENUMERATION_DEDUCE_BOUNDARY)( \
- name, __VA_ARGS__, base::HistogramBase::kUmaTargetedHistogramFlag))
+ INTERNAL_UMA_HISTOGRAM_ENUMERATION_DEDUCE_BOUNDARY) \
+ (name, __VA_ARGS__, base::HistogramBase::kUmaTargetedHistogramFlag)
// As above but "scaled" count to avoid overflows caused by increments of
// large amounts. See UMA_HISTOGRAM_SCALED_EXACT_LINEAR for more information.
@@ -257,10 +259,10 @@
name, min, max, bucket_count, \
base::HistogramBase::kUmaTargetedHistogramFlag))
-// Scoped class which logs its time on this earth as a UMA statistic. This is
-// recommended for when you want a histogram which measures the time it takes
-// for a method to execute. This measures up to 10 seconds. It uses
-// UMA_HISTOGRAM_TIMES under the hood.
+// Scoped class which logs its time on this earth in milliseconds as a UMA
+// statistic. This is recommended for when you want a histogram which measures
+// the time it takes for a method to execute. This measures up to 10 seconds. It
+// uses UMA_HISTOGRAM_TIMES under the hood.
// Sample usage:
// void Function() {
diff --git a/chromium/base/metrics/histogram_macros_local.h b/chromium/base/metrics/histogram_macros_local.h
index c4d333b5019..38a2d785202 100644
--- a/chromium/base/metrics/histogram_macros_local.h
+++ b/chromium/base/metrics/histogram_macros_local.h
@@ -19,10 +19,10 @@
// For usage details, see the equivalents in histogram_macros.h.
#define LOCAL_HISTOGRAM_ENUMERATION(name, ...) \
- CR_EXPAND_ARG(INTERNAL_UMA_HISTOGRAM_ENUMERATION_GET_MACRO( \
+ INTERNAL_UMA_HISTOGRAM_ENUMERATION_GET_MACRO( \
__VA_ARGS__, INTERNAL_UMA_HISTOGRAM_ENUMERATION_SPECIFY_BOUNDARY, \
- INTERNAL_UMA_HISTOGRAM_ENUMERATION_DEDUCE_BOUNDARY)( \
- name, __VA_ARGS__, base::HistogramBase::kNoFlags))
+ INTERNAL_UMA_HISTOGRAM_ENUMERATION_DEDUCE_BOUNDARY) \
+ (name, __VA_ARGS__, base::HistogramBase::kNoFlags)
#define LOCAL_HISTOGRAM_BOOLEAN(name, sample) \
STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
diff --git a/chromium/base/metrics/histogram_unittest.cc b/chromium/base/metrics/histogram_unittest.cc
index e516acbe2d1..0eec32b0ee2 100644
--- a/chromium/base/metrics/histogram_unittest.cc
+++ b/chromium/base/metrics/histogram_unittest.cc
@@ -295,6 +295,25 @@ TEST_P(HistogramTest, LinearRangesTest) {
EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges()));
}
+TEST_P(HistogramTest, SingleValueEnumerationHistogram) {
+ // Make sure its possible to construct a linear histogram with only the two
+ // required outlier buckets (underflow and overflow).
+ HistogramBase* histogram = LinearHistogram::FactoryGet(
+ "SingleValueEnum", 1, 1, 2, HistogramBase::kNoFlags);
+ EXPECT_TRUE(histogram);
+
+ // Make sure the macros work properly. This can only be run when
+ // there is no persistent allocator which can be discarded and leave
+ // dangling pointers.
+ if (!use_persistent_histogram_allocator_) {
+ enum EnumWithMax {
+ kSomething = 0,
+ kMaxValue = kSomething,
+ };
+ UMA_HISTOGRAM_ENUMERATION("h1", kSomething);
+ }
+}
+
TEST_P(HistogramTest, ArrayToCustomEnumRangesTest) {
const HistogramBase::Sample ranges[3] = {5, 10, 20};
std::vector<HistogramBase::Sample> ranges_vec =
diff --git a/chromium/base/metrics/persistent_histogram_storage.cc b/chromium/base/metrics/persistent_histogram_storage.cc
index e2a56d7df6c..0676e47ba18 100644
--- a/chromium/base/metrics/persistent_histogram_storage.cc
+++ b/chromium/base/metrics/persistent_histogram_storage.cc
@@ -39,8 +39,6 @@ PersistentHistogramStorage::~PersistentHistogramStorage() {
PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
allocator->UpdateTrackingHistograms();
- // TODO(chengx): Investigate making early return depend on whethere there are
- // metrics to report at this point or not.
if (disabled_)
return;
diff --git a/chromium/base/metrics/persistent_histogram_storage_unittest.cc b/chromium/base/metrics/persistent_histogram_storage_unittest.cc
index 0b9b1ce6b09..68f795a5ea9 100644
--- a/chromium/base/metrics/persistent_histogram_storage_unittest.cc
+++ b/chromium/base/metrics/persistent_histogram_storage_unittest.cc
@@ -50,9 +50,8 @@ class PersistentHistogramStorageTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(PersistentHistogramStorageTest);
};
-// TODO(chengx): Re-enable the test on OS_IOS after issue 836789 is fixed.
-// PersistentHistogramStorage is only used on OS_WIN now, so disabling this
-// test on OS_IOS is fine.
+// This test is disabled on OS_IOS because of crbug.com/836789. This is fine as
+// PersistentHistogramStorage is only used on OS_WIN now.
#if !defined(OS_NACL) && !defined(OS_IOS)
TEST_F(PersistentHistogramStorageTest, HistogramWriteTest) {
auto persistent_histogram_storage =
diff --git a/chromium/base/metrics/persistent_memory_allocator.cc b/chromium/base/metrics/persistent_memory_allocator.cc
index a8cd4a4c28e..d111ea9fde3 100644
--- a/chromium/base/metrics/persistent_memory_allocator.cc
+++ b/chromium/base/metrics/persistent_memory_allocator.cc
@@ -21,8 +21,9 @@
#include "base/metrics/histogram_functions.h"
#include "base/metrics/sparse_histogram.h"
#include "base/numerics/safe_conversions.h"
-#include "base/sys_info.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/optional.h"
+#include "base/system/sys_info.h"
+#include "base/threading/scoped_blocking_call.h"
#include "build/build_config.h"
namespace {
@@ -1068,7 +1069,7 @@ bool FilePersistentMemoryAllocator::IsFileAcceptable(
void FilePersistentMemoryAllocator::Cache() {
// Since this method is expected to load data from permanent storage
// into memory, blocking I/O may occur.
- AssertBlockingAllowed();
+ base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
// Calculate begin/end addresses so that the first byte of every page
// in that range can be read. Keep within the used space. The |volatile|
@@ -1092,14 +1093,16 @@ void FilePersistentMemoryAllocator::Cache() {
}
void FilePersistentMemoryAllocator::FlushPartial(size_t length, bool sync) {
- if (sync)
- AssertBlockingAllowed();
if (IsReadonly())
return;
+ base::Optional<base::ScopedBlockingCall> scoped_blocking_call;
+ if (sync)
+ scoped_blocking_call.emplace(base::BlockingType::MAY_BLOCK);
+
#if defined(OS_WIN)
// Windows doesn't support asynchronous flush.
- AssertBlockingAllowed();
+ scoped_blocking_call.emplace(base::BlockingType::MAY_BLOCK);
BOOL success = ::FlushViewOfFile(data(), length);
DPCHECK(success);
#elif defined(OS_MACOSX)
diff --git a/chromium/base/metrics/user_metrics.cc b/chromium/base/metrics/user_metrics.cc
index 9fcc9e8a18a..a0c88a4b8df 100644
--- a/chromium/base/metrics/user_metrics.cc
+++ b/chromium/base/metrics/user_metrics.cc
@@ -13,6 +13,7 @@
#include "base/location.h"
#include "base/macros.h"
#include "base/threading/thread_checker.h"
+#include "base/trace_event/trace_event.h"
namespace base {
namespace {
@@ -29,6 +30,7 @@ void RecordAction(const UserMetricsAction& action) {
}
void RecordComputedAction(const std::string& action) {
+ TRACE_EVENT_INSTANT1("ui", "UserEvent", TRACE_EVENT_SCOPE_GLOBAL, "action", action);
if (!g_task_runner.Get()) {
DCHECK(g_callbacks.Get().empty());
return;