Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/metrics/field_trial.h" | 5 #include "base/metrics/field_trial.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/base_switches.h" | 10 #include "base/base_switches.h" |
| 11 #include "base/build_time.h" | 11 #include "base/build_time.h" |
| 12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 13 #include "base/debug/alias.h" | 13 #include "base/debug/alias.h" |
| 14 #include "base/feature_list.h" | 14 #include "base/feature_list.h" |
| 15 #include "base/logging.h" | 15 #include "base/logging.h" |
| 16 #include "base/pickle.h" | 16 #include "base/pickle.h" |
| 17 #include "base/process/memory.h" | 17 #include "base/process/memory.h" |
| 18 #include "base/rand_util.h" | 18 #include "base/rand_util.h" |
| 19 #include "base/strings/string_number_conversions.h" | 19 #include "base/strings/string_number_conversions.h" |
| 20 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" |
| 21 #include "base/strings/stringprintf.h" | 21 #include "base/strings/stringprintf.h" |
| 22 #include "base/strings/utf_string_conversions.h" | 22 #include "base/strings/utf_string_conversions.h" |
| 23 | 23 |
| 24 // On systems that use the zygote process to spawn child processes, we must | |
| 25 // retrieve the correct fd using the mapping in GlobalDescriptors. | |
| 26 #if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_MACOSX) && \ | |
| 27 !defined(OS_ANDROID) | |
| 28 #define POSIX_WITH_ZYGOTE 1 | |
| 29 #endif | |
| 30 | |
| 31 #if defined(POSIX_WITH_ZYGOTE) | |
| 32 #include "base/posix/global_descriptors.h" | |
| 33 #endif | |
| 34 | |
| 24 namespace base { | 35 namespace base { |
| 25 | 36 |
| 26 namespace { | 37 namespace { |
| 27 | 38 |
| 28 // Define a separator character to use when creating a persistent form of an | 39 // Define a separator character to use when creating a persistent form of an |
| 29 // instance. This is intended for use as a command line argument, passed to a | 40 // instance. This is intended for use as a command line argument, passed to a |
| 30 // second process to mimic our state (i.e., provide the same group name). | 41 // second process to mimic our state (i.e., provide the same group name). |
| 31 const char kPersistentStringSeparator = '/'; // Currently a slash. | 42 const char kPersistentStringSeparator = '/'; // Currently a slash. |
| 32 | 43 |
| 33 // Define a marker character to be used as a prefix to a trial name on the | 44 // Define a marker character to be used as a prefix to a trial name on the |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 225 } | 236 } |
| 226 } | 237 } |
| 227 | 238 |
| 228 #if defined(OS_WIN) | 239 #if defined(OS_WIN) |
| 229 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { | 240 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { |
| 230 HANDLE src = allocator->shared_memory()->handle().GetHandle(); | 241 HANDLE src = allocator->shared_memory()->handle().GetHandle(); |
| 231 ProcessHandle process = GetCurrentProcess(); | 242 ProcessHandle process = GetCurrentProcess(); |
| 232 DWORD access = SECTION_MAP_READ | SECTION_QUERY; | 243 DWORD access = SECTION_MAP_READ | SECTION_QUERY; |
| 233 HANDLE dst; | 244 HANDLE dst; |
| 234 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) | 245 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) |
| 235 return nullptr; | 246 return kInvalidPlatformFile; |
| 236 return dst; | 247 return dst; |
| 237 } | 248 } |
| 238 #endif | 249 #endif |
| 239 | 250 |
| 251 #if defined(POSIX_WITH_ZYGOTE) | |
| 252 int CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { | |
| 253 SharedMemoryHandle new_handle; | |
| 254 allocator->shared_memory()->ShareReadOnlyToProcess(GetCurrentProcessHandle(), | |
| 255 &new_handle); | |
| 256 return SharedMemory::GetFdFromSharedMemoryHandle(new_handle); | |
| 257 } | |
| 258 #endif | |
| 259 | |
| 240 } // namespace | 260 } // namespace |
| 241 | 261 |
| 242 // statics | 262 // statics |
| 243 const int FieldTrial::kNotFinalized = -1; | 263 const int FieldTrial::kNotFinalized = -1; |
| 244 const int FieldTrial::kDefaultGroupNumber = 0; | 264 const int FieldTrial::kDefaultGroupNumber = 0; |
| 245 bool FieldTrial::enable_benchmarking_ = false; | 265 bool FieldTrial::enable_benchmarking_ = false; |
| 246 | 266 |
| 247 int FieldTrialList::kNoExpirationYear = 0; | 267 int FieldTrialList::kNoExpirationYear = 0; |
| 248 | 268 |
| 249 //------------------------------------------------------------------------------ | 269 //------------------------------------------------------------------------------ |
| (...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 729 // processes are properly reported in crash reports. | 749 // processes are properly reported in crash reports. |
| 730 trial->group(); | 750 trial->group(); |
| 731 } | 751 } |
| 732 } | 752 } |
| 733 return true; | 753 return true; |
| 734 } | 754 } |
| 735 | 755 |
| 736 // static | 756 // static |
| 737 void FieldTrialList::CreateTrialsFromCommandLine( | 757 void FieldTrialList::CreateTrialsFromCommandLine( |
| 738 const CommandLine& cmd_line, | 758 const CommandLine& cmd_line, |
| 739 const char* field_trial_handle_switch) { | 759 const char* field_trial_handle_switch, |
| 760 int field_trial_descriptor_id) { | |
| 740 global_->create_trials_from_command_line_called_ = true; | 761 global_->create_trials_from_command_line_called_ = true; |
| 741 | 762 |
| 742 #if defined(OS_WIN) && !defined(OS_NACL) | 763 #if defined(OS_WIN) |
| 743 if (cmd_line.HasSwitch(field_trial_handle_switch)) { | 764 if (cmd_line.HasSwitch(field_trial_handle_switch)) { |
| 744 std::string arg = cmd_line.GetSwitchValueASCII(field_trial_handle_switch); | 765 std::string handle_switch = |
| 745 int field_trial_handle = std::stoi(arg); | 766 cmd_line.GetSwitchValueASCII(field_trial_handle_switch); |
| 746 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle); | 767 bool result = CreateTrialsFromHandleSwitch(handle_switch); |
| 747 bool result = CreateTrialsFromWindowsHandle(handle); | |
| 748 DCHECK(result); | 768 DCHECK(result); |
| 749 } | 769 } |
| 750 #endif | 770 #endif |
| 751 | 771 |
| 772 #if defined(POSIX_WITH_ZYGOTE) | |
| 773 bool result = CreateTrialsFromDescriptor(field_trial_descriptor_id); | |
|
Alexei Svitkine (slow)
2016/11/29 19:32:47
Nit: Just inline this into the if.
lawrencewu
2016/11/29 19:52:44
Done.
| |
| 774 // If we failed to create trials from the descriptor, fallback to the command | |
| 775 // line. | |
| 776 if (result) | |
| 777 return; | |
| 778 #endif | |
| 779 | |
| 752 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { | 780 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { |
| 753 bool result = FieldTrialList::CreateTrialsFromString( | 781 bool result = FieldTrialList::CreateTrialsFromString( |
| 754 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), | 782 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), |
| 755 std::set<std::string>()); | 783 std::set<std::string>()); |
| 756 DCHECK(result); | 784 DCHECK(result); |
| 757 } | 785 } |
| 758 } | 786 } |
| 759 | 787 |
| 788 #if defined(POSIX_WITH_ZYGOTE) | |
| 789 // static | |
| 790 bool FieldTrialList::CreateTrialsFromDescriptor(int field_trial_descriptor_id) { | |
| 791 if (!kUseSharedMemoryForFieldTrials) | |
| 792 return false; | |
| 793 | |
| 794 if (field_trial_descriptor_id == -1) { | |
|
Alexei Svitkine (slow)
2016/11/29 19:32:47
Nit: No {}
lawrencewu
2016/11/29 19:52:44
Done.
| |
| 795 return false; | |
| 796 } | |
| 797 | |
| 798 int fd = | |
| 799 GlobalDescriptors::GetInstance()->MaybeGet(field_trial_descriptor_id); | |
| 800 if (fd == -1) | |
| 801 return false; | |
| 802 | |
| 803 global_->create_trials_from_command_line_called_ = true; | |
|
Alexei Svitkine (slow)
2016/11/29 19:32:47
This is not needed anymore since you're calling it
lawrencewu
2016/11/29 19:52:44
Removed.
| |
| 804 | |
| 805 SharedMemoryHandle shm_handle(fd, true); | |
| 806 bool result = FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle); | |
| 807 DCHECK(result); | |
| 808 return true; | |
| 809 } | |
| 810 #endif | |
| 811 | |
| 760 #if defined(OS_WIN) | 812 #if defined(OS_WIN) |
| 761 // static | 813 // static |
| 762 void FieldTrialList::AppendFieldTrialHandleIfNeeded( | 814 void FieldTrialList::AppendFieldTrialHandleIfNeeded( |
| 763 HandlesToInheritVector* handles) { | 815 HandlesToInheritVector* handles) { |
| 764 if (!global_) | 816 if (!global_) |
| 765 return; | 817 return; |
| 766 if (kUseSharedMemoryForFieldTrials) { | 818 if (kUseSharedMemoryForFieldTrials) { |
| 767 InstantiateFieldTrialAllocatorIfNeeded(); | 819 InstantiateFieldTrialAllocatorIfNeeded(); |
| 768 if (global_->readonly_allocator_handle_) | 820 if (global_->readonly_allocator_handle_) |
| 769 handles->push_back(global_->readonly_allocator_handle_); | 821 handles->push_back(global_->readonly_allocator_handle_); |
| 770 } | 822 } |
| 771 } | 823 } |
| 772 #endif | 824 #endif |
| 773 | 825 |
| 826 #if defined(OS_POSIX) && !defined(OS_NACL) | |
| 827 // static | |
| 828 int FieldTrialList::GetFieldTrialHandle() { | |
| 829 if (!global_) | |
|
Alexei Svitkine (slow)
2016/11/29 19:32:47
Does this actually get hit?
lawrencewu
2016/11/29 19:52:44
I added a log statement here and it doesn't get hi
Alexei Svitkine (slow)
2016/11/29 20:19:27
I think it would be better to remove this if it's
lawrencewu
2016/11/29 21:40:18
Actually, it looks like some tests do hit that and
| |
| 830 return kInvalidPlatformFile; | |
| 831 if (kUseSharedMemoryForFieldTrials) { | |
| 832 InstantiateFieldTrialAllocatorIfNeeded(); | |
| 833 // We check for an invalid handle where this gets called. | |
| 834 return global_->readonly_allocator_handle_; | |
| 835 } | |
| 836 return kInvalidPlatformFile; | |
| 837 } | |
| 838 #endif | |
| 839 | |
| 774 // static | 840 // static |
| 775 void FieldTrialList::CopyFieldTrialStateToFlags( | 841 void FieldTrialList::CopyFieldTrialStateToFlags( |
| 776 const char* field_trial_handle_switch, | 842 const char* field_trial_handle_switch, |
| 777 CommandLine* cmd_line) { | 843 CommandLine* cmd_line) { |
| 778 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, | 844 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, |
| 779 // content browser tests currently don't create a FieldTrialList because they | 845 // content browser tests currently don't create a FieldTrialList because they |
| 780 // don't run ChromeBrowserMainParts code where it's done for Chrome. | 846 // don't run ChromeBrowserMainParts code where it's done for Chrome. |
| 781 if (!global_) | 847 if (!global_) |
| 782 return; | 848 return; |
| 783 | 849 |
| 784 #if defined(OS_WIN) | 850 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) |
| 785 // Use shared memory to pass the state if the feature is enabled, otherwise | 851 // Use shared memory to pass the state if the feature is enabled, otherwise |
| 786 // fallback to passing it via the command line as a string. | 852 // fallback to passing it via the command line as a string. |
| 787 if (kUseSharedMemoryForFieldTrials) { | 853 if (kUseSharedMemoryForFieldTrials) { |
| 788 InstantiateFieldTrialAllocatorIfNeeded(); | 854 InstantiateFieldTrialAllocatorIfNeeded(); |
| 789 // If the readonly handle didn't get duplicated properly, then fallback to | 855 // If the readonly handle didn't get duplicated properly, then fallback to |
| 790 // original behavior. | 856 // original behavior. |
| 791 if (!global_->readonly_allocator_handle_) { | 857 if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) { |
| 792 AddForceFieldTrialsFlag(cmd_line); | 858 AddForceFieldTrialsFlag(cmd_line); |
| 793 return; | 859 return; |
| 794 } | 860 } |
| 795 | 861 |
| 796 // HANDLE is just typedef'd to void *. We basically cast the handle into an | 862 // We need to pass a named anonymous handle to shared memory over the command |
|
Alexei Svitkine (slow)
2016/11/29 19:32:47
Nit: Indent this comment.
lawrencewu
2016/11/29 19:52:44
Done.
| |
| 797 // int (uintptr_t, to be exact), stringify the int, and pass it as a | 863 // line on Windows, since the child doesn't know which of the handles it |
| 798 // command-line flag. The child process will do the reverse conversions to | 864 // inherited it should open. On POSIX, we don't need to do this -- we dup the fd |
| 799 // retrieve the handle. See http://stackoverflow.com/a/153077 | 865 // into a fixed fd kFieldTrialDescriptor, so we can just look it up there. |
| 866 #if defined(OS_WIN) | |
| 867 // PlatformFile is typedef'd to HANDLE which is typedef'd to void *. We | |
| 868 // basically cast the handle into an int (uintptr_t, to be exact), stringify | |
| 869 // the int, and pass it as a command-line flag. The child process will do | |
| 870 // the reverse conversions to retrieve the handle. See | |
| 871 // http://stackoverflow.com/a/153077 | |
| 800 auto uintptr_handle = | 872 auto uintptr_handle = |
| 801 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); | 873 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); |
| 802 std::string field_trial_handle = std::to_string(uintptr_handle); | 874 std::string field_trial_handle = std::to_string(uintptr_handle); |
| 803 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); | 875 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); |
| 876 #endif | |
| 804 global_->field_trial_allocator_->UpdateTrackingHistograms(); | 877 global_->field_trial_allocator_->UpdateTrackingHistograms(); |
|
Alexei Svitkine (slow)
2016/11/29 19:32:46
Nit: Move this line above to line 861.
lawrencewu
2016/11/29 19:52:44
Done.
| |
| 805 return; | 878 return; |
| 806 } | 879 } |
| 807 #endif | 880 #endif |
| 808 | 881 |
| 809 AddForceFieldTrialsFlag(cmd_line); | 882 AddForceFieldTrialsFlag(cmd_line); |
| 810 } | 883 } |
| 811 | 884 |
| 812 // static | 885 // static |
| 813 FieldTrial* FieldTrialList::CreateFieldTrial( | 886 FieldTrial* FieldTrialList::CreateFieldTrial( |
| 814 const std::string& name, | 887 const std::string& name, |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 887 // static | 960 // static |
| 888 size_t FieldTrialList::GetFieldTrialCount() { | 961 size_t FieldTrialList::GetFieldTrialCount() { |
| 889 if (!global_) | 962 if (!global_) |
| 890 return 0; | 963 return 0; |
| 891 AutoLock auto_lock(global_->lock_); | 964 AutoLock auto_lock(global_->lock_); |
| 892 return global_->registered_.size(); | 965 return global_->registered_.size(); |
| 893 } | 966 } |
| 894 | 967 |
| 895 #if defined(OS_WIN) | 968 #if defined(OS_WIN) |
| 896 // static | 969 // static |
| 897 bool FieldTrialList::CreateTrialsFromWindowsHandle(HANDLE handle) { | 970 bool FieldTrialList::CreateTrialsFromHandleSwitch( |
| 971 const std::string& handle_switch) { | |
| 972 int field_trial_handle = std::stoi(handle_switch); | |
| 973 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle); | |
| 898 SharedMemoryHandle shm_handle(handle, GetCurrentProcId()); | 974 SharedMemoryHandle shm_handle(handle, GetCurrentProcId()); |
| 975 return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle); | |
| 976 } | |
| 977 #endif | |
| 899 | 978 |
| 979 #if !defined(OS_NACL) | |
| 980 // static | |
| 981 bool FieldTrialList::CreateTrialsFromSharedMemoryHandle( | |
| 982 SharedMemoryHandle shm_handle) { | |
| 900 // shm gets deleted when it gets out of scope, but that's OK because we need | 983 // shm gets deleted when it gets out of scope, but that's OK because we need |
| 901 // it only for the duration of this method. | 984 // it only for the duration of this method. |
| 902 std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true)); | 985 std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true)); |
| 903 if (!shm.get()->Map(kFieldTrialAllocationSize)) | 986 if (!shm.get()->Map(kFieldTrialAllocationSize)) |
| 904 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); | 987 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); |
| 905 | 988 |
| 906 return FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm)); | 989 return FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm)); |
| 907 } | 990 } |
| 908 #endif | 991 #endif |
| 909 | 992 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 979 #if !defined(OS_NACL) | 1062 #if !defined(OS_NACL) |
| 980 // static | 1063 // static |
| 981 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() { | 1064 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() { |
| 982 if (!global_) | 1065 if (!global_) |
| 983 return; | 1066 return; |
| 984 AutoLock auto_lock(global_->lock_); | 1067 AutoLock auto_lock(global_->lock_); |
| 985 // Create the allocator if not already created and add all existing trials. | 1068 // Create the allocator if not already created and add all existing trials. |
| 986 if (global_->field_trial_allocator_ != nullptr) | 1069 if (global_->field_trial_allocator_ != nullptr) |
| 987 return; | 1070 return; |
| 988 | 1071 |
| 1072 SharedMemoryCreateOptions options; | |
| 1073 options.size = kFieldTrialAllocationSize; | |
| 1074 options.share_read_only = true; | |
| 1075 | |
| 989 std::unique_ptr<SharedMemory> shm(new SharedMemory()); | 1076 std::unique_ptr<SharedMemory> shm(new SharedMemory()); |
| 990 if (!shm->CreateAndMapAnonymous(kFieldTrialAllocationSize)) | 1077 if (!shm->Create(options)) |
| 1078 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); | |
| 1079 | |
| 1080 if (!shm->Map(kFieldTrialAllocationSize)) | |
| 991 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); | 1081 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); |
| 992 | 1082 |
| 993 global_->field_trial_allocator_.reset( | 1083 global_->field_trial_allocator_.reset( |
| 994 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); | 1084 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); |
| 995 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); | 1085 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); |
| 996 | 1086 |
| 997 // Add all existing field trials. | 1087 // Add all existing field trials. |
| 998 for (const auto& registered : global_->registered_) { | 1088 for (const auto& registered : global_->registered_) { |
| 999 AddToAllocatorWhileLocked(registered.second); | 1089 AddToAllocatorWhileLocked(registered.second); |
| 1000 } | 1090 } |
| 1001 | 1091 |
| 1002 #if defined(OS_WIN) | 1092 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) |
| 1003 // Set |readonly_allocator_handle_| so we can pass it to be inherited and | 1093 // Set |readonly_allocator_handle_| so we can pass it to be inherited and |
| 1004 // via the command line. | 1094 // via the command line. |
| 1005 global_->readonly_allocator_handle_ = | 1095 global_->readonly_allocator_handle_ = |
| 1006 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); | 1096 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); |
| 1007 #endif | 1097 #endif |
| 1008 } | 1098 } |
| 1009 #endif | 1099 #endif |
| 1010 | 1100 |
| 1011 // static | 1101 // static |
| 1012 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { | 1102 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1107 return; | 1197 return; |
| 1108 } | 1198 } |
| 1109 AutoLock auto_lock(global_->lock_); | 1199 AutoLock auto_lock(global_->lock_); |
| 1110 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1200 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
| 1111 trial->AddRef(); | 1201 trial->AddRef(); |
| 1112 trial->SetTrialRegistered(); | 1202 trial->SetTrialRegistered(); |
| 1113 global_->registered_[trial->trial_name()] = trial; | 1203 global_->registered_[trial->trial_name()] = trial; |
| 1114 } | 1204 } |
| 1115 | 1205 |
| 1116 } // namespace base | 1206 } // namespace base |
| OLD | NEW |