Index: base/metrics/field_trial.cc |
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc |
index 78602f1e613d39f00020dea6f1f18f093bcfa72f..5711aec2373483c3944192d108cf04e9a15eafb9 100644 |
--- a/base/metrics/field_trial.cc |
+++ b/base/metrics/field_trial.cc |
@@ -16,6 +16,7 @@ |
#include "base/process/memory.h" |
#include "base/rand_util.h" |
#include "base/strings/string_number_conversions.h" |
+#include "base/strings/string_split.h" |
#include "base/strings/string_util.h" |
#include "base/strings/stringprintf.h" |
#include "base/strings/utf_string_conversions.h" |
@@ -208,25 +209,6 @@ void AddFeatureAndFieldTrialFlags(const char* enable_features_switch, |
} |
} |
-#if defined(OS_WIN) |
-HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { |
- HANDLE src = allocator->shared_memory()->handle().GetHandle(); |
- ProcessHandle process = GetCurrentProcess(); |
- DWORD access = SECTION_MAP_READ | SECTION_QUERY; |
- HANDLE dst; |
- if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) |
- return kInvalidPlatformFile; |
- return dst; |
-} |
-#endif |
- |
-#if defined(OS_POSIX) && !defined(OS_NACL) |
-int CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { |
- SharedMemoryHandle handle = allocator->shared_memory()->GetReadOnlyHandle(); |
- return SharedMemory::GetFdFromSharedMemoryHandle(handle); |
-} |
-#endif |
- |
void OnOutOfMemory(size_t size) { |
#if defined(OS_NACL) |
NOTREACHED(); |
@@ -235,6 +217,23 @@ void OnOutOfMemory(size_t size) { |
#endif |
} |
+#if !defined(OS_NACL) |
+// Returns whether the operation succeeded. |
+bool DeserializeGUIDFromStringPieces(base::StringPiece first, |
+ base::StringPiece second, |
+ base::UnguessableToken* guid) { |
+ uint64_t high = 0; |
+ uint64_t low = 0; |
+ if (!base::StringToUint64(first, &high) || |
+ !base::StringToUint64(second, &low)) { |
+ return false; |
+ } |
+ |
+ *guid = base::UnguessableToken::Deserialize(high, low); |
+ return true; |
+} |
+#endif |
+ |
} // namespace |
// statics |
@@ -781,9 +780,9 @@ void FieldTrialList::CreateTrialsFromCommandLine( |
#if defined(OS_WIN) |
if (cmd_line.HasSwitch(field_trial_handle_switch)) { |
- std::string handle_switch = |
+ std::string switch_value = |
cmd_line.GetSwitchValueASCII(field_trial_handle_switch); |
- bool result = CreateTrialsFromHandleSwitch(handle_switch); |
+ bool result = CreateTrialsFromSwitchValue(switch_value); |
DCHECK(result); |
} |
#endif |
@@ -793,7 +792,9 @@ void FieldTrialList::CreateTrialsFromCommandLine( |
// sent over the switch (we don't care about the value). Invalid handles |
// occur in some browser tests which don't initialize the allocator. |
if (cmd_line.HasSwitch(field_trial_handle_switch)) { |
- bool result = CreateTrialsFromDescriptor(fd_key); |
+ std::string switch_value = |
+ cmd_line.GetSwitchValueASCII(field_trial_handle_switch); |
+ bool result = CreateTrialsFromDescriptor(fd_key, switch_value); |
DCHECK(result); |
} |
#endif |
@@ -832,21 +833,21 @@ void FieldTrialList::AppendFieldTrialHandleIfNeeded( |
return; |
if (kUseSharedMemoryForFieldTrials) { |
InstantiateFieldTrialAllocatorIfNeeded(); |
- if (global_->readonly_allocator_handle_) |
- handles->push_back(global_->readonly_allocator_handle_); |
+ if (global_->readonly_allocator_handle_.IsValid()) |
+ handles->push_back(global_->readonly_allocator_handle_.GetHandle()); |
} |
} |
#endif |
#if defined(OS_POSIX) && !defined(OS_NACL) |
// static |
-int FieldTrialList::GetFieldTrialHandle() { |
+SharedMemoryHandle FieldTrialList::GetFieldTrialHandle() { |
if (global_ && kUseSharedMemoryForFieldTrials) { |
InstantiateFieldTrialAllocatorIfNeeded(); |
// We check for an invalid handle where this gets called. |
return global_->readonly_allocator_handle_; |
} |
- return kInvalidPlatformFile; |
+ return SharedMemoryHandle(); |
} |
#endif |
@@ -873,37 +874,16 @@ void FieldTrialList::CopyFieldTrialStateToFlags( |
InstantiateFieldTrialAllocatorIfNeeded(); |
// If the readonly handle didn't get duplicated properly, then fallback to |
// original behavior. |
- if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) { |
+ if (!global_->readonly_allocator_handle_.IsValid()) { |
AddFeatureAndFieldTrialFlags(enable_features_switch, |
disable_features_switch, cmd_line); |
return; |
} |
global_->field_trial_allocator_->UpdateTrackingHistograms(); |
- |
-#if defined(OS_WIN) |
- // We need to pass a named anonymous handle to shared memory over the |
- // command line on Windows, since the child doesn't know which of the |
- // handles it inherited it should open. |
- // PlatformFile is typedef'd to HANDLE which is typedef'd to void *. We |
- // basically cast the handle into an int (uintptr_t, to be exact), stringify |
- // the int, and pass it as a command-line flag. The child process will do |
- // the reverse conversions to retrieve the handle. See |
- // http://stackoverflow.com/a/153077 |
- auto uintptr_handle = |
- reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); |
- std::string field_trial_handle = std::to_string(uintptr_handle); |
- cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); |
-#elif defined(OS_POSIX) |
- // On POSIX, we dup the fd into a fixed fd kFieldTrialDescriptor, so we |
- // don't have to pass over the handle (it's not even the right handle |
- // anyways). But some browser tests don't create the allocator, so we need |
- // to be able to distinguish valid and invalid handles. We do that by just |
- // checking that the flag is set with a dummy value. |
- cmd_line->AppendSwitchASCII(field_trial_handle_switch, "1"); |
-#else |
-#error Unsupported OS |
-#endif |
+ std::string switch_value = SerializeSharedMemoryHandleMetadata( |
+ global_->readonly_allocator_handle_); |
+ cmd_line->AppendSwitchASCII(field_trial_handle_switch, switch_value); |
return; |
} |
@@ -1132,22 +1112,81 @@ FieldTrialList::GetAllFieldTrialsFromPersistentAllocator( |
return entries; |
} |
+// static |
+std::string FieldTrialList::SerializeSharedMemoryHandleMetadata( |
+ const SharedMemoryHandle& shm) { |
+ std::stringstream ss; |
+#if defined(OS_WIN) |
+ // Tell the child process the name of the inherited HANDLE. |
+ uintptr_t uintptr_handle = reinterpret_cast<uintptr_t>(shm.GetHandle()); |
+ ss << uintptr_handle << ","; |
+#elif !defined(OS_POSIX) |
+#error Unsupported OS |
+#endif |
+ |
+ base::UnguessableToken guid = shm.GetGUID(); |
+ ss << guid.GetHighForSerialization() << "," << guid.GetLowForSerialization(); |
+ return ss.str(); |
+} |
+ |
#if defined(OS_WIN) |
// static |
-bool FieldTrialList::CreateTrialsFromHandleSwitch( |
- const std::string& handle_switch) { |
- int field_trial_handle = std::stoi(handle_switch); |
+SharedMemoryHandle FieldTrialList::DeserializeSharedMemoryHandleMetadata( |
+ const std::string& switch_value) { |
+ std::vector<base::StringPiece> tokens = base::SplitStringPiece( |
+ switch_value, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); |
+ |
+ if (tokens.size() != 3) |
+ return SharedMemoryHandle(); |
+ |
+ int field_trial_handle = 0; |
+ if (!base::StringToInt(tokens[0], &field_trial_handle)) |
+ return SharedMemoryHandle(); |
HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle); |
- // TODO(erikchen): Plumb a GUID for this SharedMemoryHandle. |
- // https://crbug.com/713763. |
- SharedMemoryHandle shm_handle(handle, base::UnguessableToken::Create()); |
- return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle); |
+ |
+ base::UnguessableToken guid; |
+ if (!DeserializeGUIDFromStringPieces(tokens[1], tokens[2], &guid)) |
+ return SharedMemoryHandle(); |
+ |
+ return SharedMemoryHandle(handle, guid); |
} |
-#endif |
+#endif // defined(OS_WIN) |
+ |
+#if defined(OS_POSIX) && !defined(OS_NACL) |
+// static |
+SharedMemoryHandle FieldTrialList::DeserializeSharedMemoryHandleMetadata( |
+ int fd, |
+ const std::string& switch_value) { |
+ std::vector<base::StringPiece> tokens = base::SplitStringPiece( |
+ switch_value, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); |
+ |
+ if (tokens.size() != 2) |
+ return SharedMemoryHandle(); |
+ |
+ base::UnguessableToken guid; |
+ if (!DeserializeGUIDFromStringPieces(tokens[0], tokens[1], &guid)) |
+ return SharedMemoryHandle(); |
+ |
+ return SharedMemoryHandle(FileDescriptor(fd, true), guid); |
+} |
+#endif // defined(OS_POSIX) && !defined(OS_NACL) |
+ |
+#if defined(OS_WIN) |
+// static |
+bool FieldTrialList::CreateTrialsFromSwitchValue( |
+ const std::string& switch_value) { |
+ SharedMemoryHandle shm = DeserializeSharedMemoryHandleMetadata(switch_value); |
+ if (!shm.IsValid()) |
+ return false; |
+ return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm); |
+} |
+#endif // defined(OS_WIN) |
#if defined(OS_POSIX) && !defined(OS_NACL) |
// static |
-bool FieldTrialList::CreateTrialsFromDescriptor(int fd_key) { |
+bool FieldTrialList::CreateTrialsFromDescriptor( |
+ int fd_key, |
+ const std::string& switch_value) { |
if (!kUseSharedMemoryForFieldTrials) |
return false; |
@@ -1158,16 +1197,16 @@ bool FieldTrialList::CreateTrialsFromDescriptor(int fd_key) { |
if (fd == -1) |
return false; |
- // TODO(erikchen): Plumb a GUID for this SharedMemoryHandle. |
- // https://crbug.com/713763. |
- SharedMemoryHandle shm_handle(FileDescriptor(fd, true), |
- base::UnguessableToken::Create()); |
+ SharedMemoryHandle shm = |
+ DeserializeSharedMemoryHandleMetadata(fd, switch_value); |
+ if (!shm.IsValid()) |
+ return false; |
- bool result = FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle); |
+ bool result = FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm); |
DCHECK(result); |
return true; |
} |
-#endif |
+#endif // defined(OS_POSIX) && !defined(OS_NACL) |
// static |
bool FieldTrialList::CreateTrialsFromSharedMemoryHandle( |
@@ -1254,7 +1293,7 @@ void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() { |
// Set |readonly_allocator_handle_| so we can pass it to be inherited and |
// via the command line. |
global_->readonly_allocator_handle_ = |
- CreateReadOnlyHandle(global_->field_trial_allocator_.get()); |
+ global_->field_trial_allocator_->shared_memory()->GetReadOnlyHandle(); |
#endif |
} |