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/feature_list.h" | |
| 14 #include "base/logging.h" | 13 #include "base/logging.h" |
| 15 #include "base/metrics/field_trial_param_associator.h" | 14 #include "base/metrics/field_trial_param_associator.h" |
| 16 #include "base/pickle.h" | 15 #include "base/pickle.h" |
| 17 #include "base/process/memory.h" | 16 #include "base/process/memory.h" |
| 18 #include "base/rand_util.h" | 17 #include "base/rand_util.h" |
| 19 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
| 20 #include "base/strings/string_util.h" | 19 #include "base/strings/string_util.h" |
| 21 #include "base/strings/stringprintf.h" | 20 #include "base/strings/stringprintf.h" |
| 22 #include "base/strings/utf_string_conversions.h" | 21 #include "base/strings/utf_string_conversions.h" |
| 23 | 22 |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 241 trials_string_piece.substr(next_item, name_end - next_item); | 240 trials_string_piece.substr(next_item, name_end - next_item); |
| 242 entry.group_name = | 241 entry.group_name = |
| 243 trials_string_piece.substr(name_end + 1, group_name_end - name_end - 1); | 242 trials_string_piece.substr(name_end + 1, group_name_end - name_end - 1); |
| 244 next_item = group_name_end + 1; | 243 next_item = group_name_end + 1; |
| 245 | 244 |
| 246 entries->push_back(std::move(entry)); | 245 entries->push_back(std::move(entry)); |
| 247 } | 246 } |
| 248 return true; | 247 return true; |
| 249 } | 248 } |
| 250 | 249 |
| 251 void AddForceFieldTrialsFlag(CommandLine* cmd_line) { | 250 void AddFeatureAndFieldTrialFlags(const char* enable_features_switch, |
| 251 const char* disable_features_switch, | |
| 252 CommandLine* cmd_line) { | |
| 253 std::string enabled_features; | |
| 254 std::string disabled_features; | |
| 255 FeatureList::GetInstance()->GetFeatureOverrides(&enabled_features, | |
| 256 &disabled_features); | |
| 257 | |
| 258 if (!enabled_features.empty()) | |
| 259 cmd_line->AppendSwitchASCII(enable_features_switch, enabled_features); | |
| 260 if (!disabled_features.empty()) | |
| 261 cmd_line->AppendSwitchASCII(disable_features_switch, disabled_features); | |
| 262 | |
| 252 std::string field_trial_states; | 263 std::string field_trial_states; |
| 253 FieldTrialList::AllStatesToString(&field_trial_states); | 264 FieldTrialList::AllStatesToString(&field_trial_states); |
| 254 if (!field_trial_states.empty()) { | 265 if (!field_trial_states.empty()) { |
| 255 cmd_line->AppendSwitchASCII(switches::kForceFieldTrials, | 266 cmd_line->AppendSwitchASCII(switches::kForceFieldTrials, |
| 256 field_trial_states); | 267 field_trial_states); |
| 257 } | 268 } |
| 258 } | 269 } |
| 259 | 270 |
| 260 #if defined(OS_WIN) | 271 #if defined(OS_WIN) |
| 261 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { | 272 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { |
| (...skipping 536 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 798 #endif | 809 #endif |
| 799 | 810 |
| 800 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { | 811 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { |
| 801 bool result = FieldTrialList::CreateTrialsFromString( | 812 bool result = FieldTrialList::CreateTrialsFromString( |
| 802 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), | 813 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), |
| 803 std::set<std::string>()); | 814 std::set<std::string>()); |
| 804 DCHECK(result); | 815 DCHECK(result); |
| 805 } | 816 } |
| 806 } | 817 } |
| 807 | 818 |
| 819 // static | |
| 820 void FieldTrialList::CreateFeaturesFromCommandLine( | |
| 821 const base::CommandLine& command_line, | |
| 822 const char* enable_features_switch, | |
| 823 const char* disable_features_switch, | |
| 824 FeatureList* feature_list) { | |
| 825 // Fallback to command line if not using shared memory. | |
| 826 if (!kUseSharedMemoryForFieldTrials || | |
| 827 !global_->field_trial_allocator_.get()) { | |
| 828 return feature_list->InitializeFromCommandLine( | |
| 829 command_line.GetSwitchValueASCII(enable_features_switch), | |
| 830 command_line.GetSwitchValueASCII(disable_features_switch)); | |
| 831 } | |
| 832 | |
| 833 feature_list->InitializeFromSharedMemory( | |
| 834 global_->field_trial_allocator_.get()); | |
| 835 } | |
| 836 | |
| 808 #if defined(POSIX_WITH_ZYGOTE) | 837 #if defined(POSIX_WITH_ZYGOTE) |
| 809 // static | 838 // static |
| 810 bool FieldTrialList::CreateTrialsFromDescriptor(int fd_key) { | 839 bool FieldTrialList::CreateTrialsFromDescriptor(int fd_key) { |
| 811 if (!kUseSharedMemoryForFieldTrials) | 840 if (!kUseSharedMemoryForFieldTrials) |
| 812 return false; | 841 return false; |
| 813 | 842 |
| 814 if (fd_key == -1) | 843 if (fd_key == -1) |
| 815 return false; | 844 return false; |
| 816 | 845 |
| 817 int fd = GlobalDescriptors::GetInstance()->MaybeGet(fd_key); | 846 int fd = GlobalDescriptors::GetInstance()->MaybeGet(fd_key); |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 847 // We check for an invalid handle where this gets called. | 876 // We check for an invalid handle where this gets called. |
| 848 return global_->readonly_allocator_handle_; | 877 return global_->readonly_allocator_handle_; |
| 849 } | 878 } |
| 850 return kInvalidPlatformFile; | 879 return kInvalidPlatformFile; |
| 851 } | 880 } |
| 852 #endif | 881 #endif |
| 853 | 882 |
| 854 // static | 883 // static |
| 855 void FieldTrialList::CopyFieldTrialStateToFlags( | 884 void FieldTrialList::CopyFieldTrialStateToFlags( |
| 856 const char* field_trial_handle_switch, | 885 const char* field_trial_handle_switch, |
| 886 const char* enable_features_switch, | |
| 887 const char* disable_features_switch, | |
| 857 CommandLine* cmd_line) { | 888 CommandLine* cmd_line) { |
| 858 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, | 889 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, |
| 859 // content browser tests currently don't create a FieldTrialList because they | 890 // content browser tests currently don't create a FieldTrialList because they |
| 860 // don't run ChromeBrowserMainParts code where it's done for Chrome. | 891 // don't run ChromeBrowserMainParts code where it's done for Chrome. |
| 861 if (!global_) | 892 // Some tests depend on the enable and disable features flag switch, though, |
| 862 return; | 893 // so we can still add those even though AllStatesToString() will be a no-op. |
| 894 if (!global_) { | |
| 895 return AddFeatureAndFieldTrialFlags(enable_features_switch, | |
|
Alexei Svitkine (slow)
2016/12/02 20:14:28
The function return value is void - so don't retur
lawrencewu
2016/12/02 20:36:32
Done.
| |
| 896 disable_features_switch, cmd_line); | |
| 897 } | |
| 863 | 898 |
| 864 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) | 899 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) |
| 865 // Use shared memory to pass the state if the feature is enabled, otherwise | 900 // Use shared memory to pass the state if the feature is enabled, otherwise |
| 866 // fallback to passing it via the command line as a string. | 901 // fallback to passing it via the command line as a string. |
| 867 if (kUseSharedMemoryForFieldTrials) { | 902 if (kUseSharedMemoryForFieldTrials) { |
| 868 InstantiateFieldTrialAllocatorIfNeeded(); | 903 InstantiateFieldTrialAllocatorIfNeeded(); |
| 869 // If the readonly handle didn't get duplicated properly, then fallback to | 904 // If the readonly handle didn't get duplicated properly, then fallback to |
| 870 // original behavior. | 905 // original behavior. |
| 871 if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) { | 906 if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) { |
| 872 AddForceFieldTrialsFlag(cmd_line); | 907 AddFeatureAndFieldTrialFlags(enable_features_switch, |
| 908 disable_features_switch, cmd_line); | |
| 873 return; | 909 return; |
| 874 } | 910 } |
| 875 | 911 |
| 876 global_->field_trial_allocator_->UpdateTrackingHistograms(); | 912 global_->field_trial_allocator_->UpdateTrackingHistograms(); |
| 877 | 913 |
| 878 #if defined(OS_WIN) | 914 #if defined(OS_WIN) |
| 879 // We need to pass a named anonymous handle to shared memory over the | 915 // We need to pass a named anonymous handle to shared memory over the |
| 880 // command line on Windows, since the child doesn't know which of the | 916 // command line on Windows, since the child doesn't know which of the |
| 881 // handles it inherited it should open. On POSIX, we don't need to do this | 917 // handles it inherited it should open. On POSIX, we don't need to do this |
| 882 // -- we dup the fd into a fixed fd kFieldTrialDescriptor, so we can just | 918 // -- we dup the fd into a fixed fd kFieldTrialDescriptor, so we can just |
| 883 // look it up there. | 919 // look it up there. |
| 884 // PlatformFile is typedef'd to HANDLE which is typedef'd to void *. We | 920 // PlatformFile is typedef'd to HANDLE which is typedef'd to void *. We |
| 885 // basically cast the handle into an int (uintptr_t, to be exact), stringify | 921 // basically cast the handle into an int (uintptr_t, to be exact), stringify |
| 886 // the int, and pass it as a command-line flag. The child process will do | 922 // the int, and pass it as a command-line flag. The child process will do |
| 887 // the reverse conversions to retrieve the handle. See | 923 // the reverse conversions to retrieve the handle. See |
| 888 // http://stackoverflow.com/a/153077 | 924 // http://stackoverflow.com/a/153077 |
| 889 auto uintptr_handle = | 925 auto uintptr_handle = |
| 890 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); | 926 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); |
| 891 std::string field_trial_handle = std::to_string(uintptr_handle); | 927 std::string field_trial_handle = std::to_string(uintptr_handle); |
| 892 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); | 928 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); |
| 893 #endif | 929 #endif |
| 894 return; | 930 return; |
| 895 } | 931 } |
| 896 #endif | 932 #endif |
| 897 | 933 |
| 898 AddForceFieldTrialsFlag(cmd_line); | 934 AddFeatureAndFieldTrialFlags(enable_features_switch, disable_features_switch, |
| 935 cmd_line); | |
| 899 } | 936 } |
| 900 | 937 |
| 901 // static | 938 // static |
| 902 FieldTrial* FieldTrialList::CreateFieldTrial( | 939 FieldTrial* FieldTrialList::CreateFieldTrial( |
| 903 const std::string& name, | 940 const std::string& name, |
| 904 const std::string& group_name) { | 941 const std::string& group_name) { |
| 905 DCHECK(global_); | 942 DCHECK(global_); |
| 906 DCHECK_GE(name.size(), 0u); | 943 DCHECK_GE(name.size(), 0u); |
| 907 DCHECK_GE(group_name.size(), 0u); | 944 DCHECK_GE(group_name.size(), 0u); |
| 908 if (name.empty() || group_name.empty() || !global_) | 945 if (name.empty() || group_name.empty() || !global_) |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1164 | 1201 |
| 1165 global_->field_trial_allocator_.reset( | 1202 global_->field_trial_allocator_.reset( |
| 1166 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); | 1203 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); |
| 1167 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); | 1204 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); |
| 1168 | 1205 |
| 1169 // Add all existing field trials. | 1206 // Add all existing field trials. |
| 1170 for (const auto& registered : global_->registered_) { | 1207 for (const auto& registered : global_->registered_) { |
| 1171 AddToAllocatorWhileLocked(registered.second); | 1208 AddToAllocatorWhileLocked(registered.second); |
| 1172 } | 1209 } |
| 1173 | 1210 |
| 1211 // Add all existing features. | |
| 1212 FeatureList::GetInstance()->AddFeaturesToAllocator( | |
| 1213 global_->field_trial_allocator_.get()); | |
| 1214 | |
| 1174 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) | 1215 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) |
| 1175 // Set |readonly_allocator_handle_| so we can pass it to be inherited and | 1216 // Set |readonly_allocator_handle_| so we can pass it to be inherited and |
| 1176 // via the command line. | 1217 // via the command line. |
| 1177 global_->readonly_allocator_handle_ = | 1218 global_->readonly_allocator_handle_ = |
| 1178 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); | 1219 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); |
| 1179 #endif | 1220 #endif |
| 1180 } | 1221 } |
| 1181 #endif | 1222 #endif |
| 1182 | 1223 |
| 1183 // static | 1224 // static |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1279 return; | 1320 return; |
| 1280 } | 1321 } |
| 1281 AutoLock auto_lock(global_->lock_); | 1322 AutoLock auto_lock(global_->lock_); |
| 1282 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1323 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
| 1283 trial->AddRef(); | 1324 trial->AddRef(); |
| 1284 trial->SetTrialRegistered(); | 1325 trial->SetTrialRegistered(); |
| 1285 global_->registered_[trial->trial_name()] = trial; | 1326 global_->registered_[trial->trial_name()] = trial; |
| 1286 } | 1327 } |
| 1287 | 1328 |
| 1288 } // namespace base | 1329 } // namespace base |
| OLD | NEW |