| 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/pickle.h" | 14 #include "base/pickle.h" |
| 16 #include "base/process/memory.h" | 15 #include "base/process/memory.h" |
| 17 #include "base/rand_util.h" | 16 #include "base/rand_util.h" |
| 18 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
| 19 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
| 20 #include "base/strings/stringprintf.h" | 19 #include "base/strings/stringprintf.h" |
| 21 #include "base/strings/utf_string_conversions.h" | 20 #include "base/strings/utf_string_conversions.h" |
| 22 | 21 |
| 23 // On systems that use the zygote process to spawn child processes, we must | 22 // On systems that use the zygote process to spawn child processes, we must |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 177 trials_string_piece.substr(next_item, name_end - next_item); | 176 trials_string_piece.substr(next_item, name_end - next_item); |
| 178 entry.group_name = | 177 entry.group_name = |
| 179 trials_string_piece.substr(name_end + 1, group_name_end - name_end - 1); | 178 trials_string_piece.substr(name_end + 1, group_name_end - name_end - 1); |
| 180 next_item = group_name_end + 1; | 179 next_item = group_name_end + 1; |
| 181 | 180 |
| 182 entries->push_back(std::move(entry)); | 181 entries->push_back(std::move(entry)); |
| 183 } | 182 } |
| 184 return true; | 183 return true; |
| 185 } | 184 } |
| 186 | 185 |
| 187 void AddForceFieldTrialsFlag(CommandLine* cmd_line) { | 186 void AddFeatureAndFieldTrialFlags(const char* enable_features_switch, |
| 187 const char* disable_features_switch, |
| 188 CommandLine* cmd_line) { |
| 189 std::string enabled_features; |
| 190 std::string disabled_features; |
| 191 FeatureList::GetInstance()->GetFeatureOverrides(&enabled_features, |
| 192 &disabled_features); |
| 193 |
| 194 if (!enabled_features.empty()) |
| 195 cmd_line->AppendSwitchASCII(enable_features_switch, enabled_features); |
| 196 if (!disabled_features.empty()) |
| 197 cmd_line->AppendSwitchASCII(disable_features_switch, disabled_features); |
| 198 |
| 188 std::string field_trial_states; | 199 std::string field_trial_states; |
| 189 FieldTrialList::AllStatesToString(&field_trial_states); | 200 FieldTrialList::AllStatesToString(&field_trial_states); |
| 190 if (!field_trial_states.empty()) { | 201 if (!field_trial_states.empty()) { |
| 191 cmd_line->AppendSwitchASCII(switches::kForceFieldTrials, | 202 cmd_line->AppendSwitchASCII(switches::kForceFieldTrials, |
| 192 field_trial_states); | 203 field_trial_states); |
| 193 } | 204 } |
| 194 } | 205 } |
| 195 | 206 |
| 196 #if defined(OS_WIN) | 207 #if defined(OS_WIN) |
| 197 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { | 208 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { |
| (...skipping 536 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 734 #endif | 745 #endif |
| 735 | 746 |
| 736 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { | 747 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { |
| 737 bool result = FieldTrialList::CreateTrialsFromString( | 748 bool result = FieldTrialList::CreateTrialsFromString( |
| 738 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), | 749 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), |
| 739 std::set<std::string>()); | 750 std::set<std::string>()); |
| 740 DCHECK(result); | 751 DCHECK(result); |
| 741 } | 752 } |
| 742 } | 753 } |
| 743 | 754 |
| 755 // static |
| 756 void FieldTrialList::CreateFeaturesFromCommandLine( |
| 757 const base::CommandLine& command_line, |
| 758 const char* enable_features_switch, |
| 759 const char* disable_features_switch, |
| 760 FeatureList* feature_list) { |
| 761 // Fallback to command line if not using shared memory. |
| 762 if (!kUseSharedMemoryForFieldTrials || |
| 763 !global_->field_trial_allocator_.get()) { |
| 764 return feature_list->InitializeFromCommandLine( |
| 765 command_line.GetSwitchValueASCII(enable_features_switch), |
| 766 command_line.GetSwitchValueASCII(disable_features_switch)); |
| 767 } |
| 768 |
| 769 feature_list->InitializeFromSharedMemory( |
| 770 global_->field_trial_allocator_.get()); |
| 771 } |
| 772 |
| 744 #if defined(POSIX_WITH_ZYGOTE) | 773 #if defined(POSIX_WITH_ZYGOTE) |
| 745 // static | 774 // static |
| 746 bool FieldTrialList::CreateTrialsFromDescriptor(int fd_key) { | 775 bool FieldTrialList::CreateTrialsFromDescriptor(int fd_key) { |
| 747 if (!kUseSharedMemoryForFieldTrials) | 776 if (!kUseSharedMemoryForFieldTrials) |
| 748 return false; | 777 return false; |
| 749 | 778 |
| 750 if (fd_key == -1) | 779 if (fd_key == -1) |
| 751 return false; | 780 return false; |
| 752 | 781 |
| 753 int fd = GlobalDescriptors::GetInstance()->MaybeGet(fd_key); | 782 int fd = GlobalDescriptors::GetInstance()->MaybeGet(fd_key); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 783 // We check for an invalid handle where this gets called. | 812 // We check for an invalid handle where this gets called. |
| 784 return global_->readonly_allocator_handle_; | 813 return global_->readonly_allocator_handle_; |
| 785 } | 814 } |
| 786 return kInvalidPlatformFile; | 815 return kInvalidPlatformFile; |
| 787 } | 816 } |
| 788 #endif | 817 #endif |
| 789 | 818 |
| 790 // static | 819 // static |
| 791 void FieldTrialList::CopyFieldTrialStateToFlags( | 820 void FieldTrialList::CopyFieldTrialStateToFlags( |
| 792 const char* field_trial_handle_switch, | 821 const char* field_trial_handle_switch, |
| 822 const char* enable_features_switch, |
| 823 const char* disable_features_switch, |
| 793 CommandLine* cmd_line) { | 824 CommandLine* cmd_line) { |
| 794 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, | 825 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, |
| 795 // content browser tests currently don't create a FieldTrialList because they | 826 // content browser tests currently don't create a FieldTrialList because they |
| 796 // don't run ChromeBrowserMainParts code where it's done for Chrome. | 827 // don't run ChromeBrowserMainParts code where it's done for Chrome. |
| 797 if (!global_) | 828 if (!global_) |
| 798 return; | 829 return; |
| 799 | 830 |
| 800 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) | 831 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) |
| 801 // Use shared memory to pass the state if the feature is enabled, otherwise | 832 // Use shared memory to pass the state if the feature is enabled, otherwise |
| 802 // fallback to passing it via the command line as a string. | 833 // fallback to passing it via the command line as a string. |
| 803 if (kUseSharedMemoryForFieldTrials) { | 834 if (kUseSharedMemoryForFieldTrials) { |
| 804 InstantiateFieldTrialAllocatorIfNeeded(); | 835 InstantiateFieldTrialAllocatorIfNeeded(); |
| 805 // If the readonly handle didn't get duplicated properly, then fallback to | 836 // If the readonly handle didn't get duplicated properly, then fallback to |
| 806 // original behavior. | 837 // original behavior. |
| 807 if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) { | 838 if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) { |
| 808 AddForceFieldTrialsFlag(cmd_line); | 839 AddFeatureAndFieldTrialFlags(enable_features_switch, |
| 840 disable_features_switch, cmd_line); |
| 809 return; | 841 return; |
| 810 } | 842 } |
| 811 | 843 |
| 812 global_->field_trial_allocator_->UpdateTrackingHistograms(); | 844 global_->field_trial_allocator_->UpdateTrackingHistograms(); |
| 813 | 845 |
| 814 #if defined(OS_WIN) | 846 #if defined(OS_WIN) |
| 815 // We need to pass a named anonymous handle to shared memory over the | 847 // We need to pass a named anonymous handle to shared memory over the |
| 816 // command line on Windows, since the child doesn't know which of the | 848 // command line on Windows, since the child doesn't know which of the |
| 817 // handles it inherited it should open. On POSIX, we don't need to do this | 849 // handles it inherited it should open. On POSIX, we don't need to do this |
| 818 // -- we dup the fd into a fixed fd kFieldTrialDescriptor, so we can just | 850 // -- we dup the fd into a fixed fd kFieldTrialDescriptor, so we can just |
| 819 // look it up there. | 851 // look it up there. |
| 820 // PlatformFile is typedef'd to HANDLE which is typedef'd to void *. We | 852 // PlatformFile is typedef'd to HANDLE which is typedef'd to void *. We |
| 821 // basically cast the handle into an int (uintptr_t, to be exact), stringify | 853 // basically cast the handle into an int (uintptr_t, to be exact), stringify |
| 822 // the int, and pass it as a command-line flag. The child process will do | 854 // the int, and pass it as a command-line flag. The child process will do |
| 823 // the reverse conversions to retrieve the handle. See | 855 // the reverse conversions to retrieve the handle. See |
| 824 // http://stackoverflow.com/a/153077 | 856 // http://stackoverflow.com/a/153077 |
| 825 auto uintptr_handle = | 857 auto uintptr_handle = |
| 826 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); | 858 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); |
| 827 std::string field_trial_handle = std::to_string(uintptr_handle); | 859 std::string field_trial_handle = std::to_string(uintptr_handle); |
| 828 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); | 860 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); |
| 829 #endif | 861 #endif |
| 830 return; | 862 return; |
| 831 } | 863 } |
| 832 #endif | 864 #endif |
| 833 | 865 |
| 834 AddForceFieldTrialsFlag(cmd_line); | 866 AddFeatureAndFieldTrialFlags(enable_features_switch, disable_features_switch, |
| 867 cmd_line); |
| 835 } | 868 } |
| 836 | 869 |
| 837 // static | 870 // static |
| 838 FieldTrial* FieldTrialList::CreateFieldTrial( | 871 FieldTrial* FieldTrialList::CreateFieldTrial( |
| 839 const std::string& name, | 872 const std::string& name, |
| 840 const std::string& group_name) { | 873 const std::string& group_name) { |
| 841 DCHECK(global_); | 874 DCHECK(global_); |
| 842 DCHECK_GE(name.size(), 0u); | 875 DCHECK_GE(name.size(), 0u); |
| 843 DCHECK_GE(group_name.size(), 0u); | 876 DCHECK_GE(group_name.size(), 0u); |
| 844 if (name.empty() || group_name.empty() || !global_) | 877 if (name.empty() || group_name.empty() || !global_) |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1000 | 1033 |
| 1001 global_->field_trial_allocator_.reset( | 1034 global_->field_trial_allocator_.reset( |
| 1002 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); | 1035 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); |
| 1003 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); | 1036 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); |
| 1004 | 1037 |
| 1005 // Add all existing field trials. | 1038 // Add all existing field trials. |
| 1006 for (const auto& registered : global_->registered_) { | 1039 for (const auto& registered : global_->registered_) { |
| 1007 AddToAllocatorWhileLocked(registered.second); | 1040 AddToAllocatorWhileLocked(registered.second); |
| 1008 } | 1041 } |
| 1009 | 1042 |
| 1043 // Add all existing features. |
| 1044 FeatureList::GetInstance()->AddFeaturesToAllocator( |
| 1045 global_->field_trial_allocator_.get()); |
| 1046 |
| 1010 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) | 1047 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) |
| 1011 // Set |readonly_allocator_handle_| so we can pass it to be inherited and | 1048 // Set |readonly_allocator_handle_| so we can pass it to be inherited and |
| 1012 // via the command line. | 1049 // via the command line. |
| 1013 global_->readonly_allocator_handle_ = | 1050 global_->readonly_allocator_handle_ = |
| 1014 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); | 1051 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); |
| 1015 #endif | 1052 #endif |
| 1016 } | 1053 } |
| 1017 #endif | 1054 #endif |
| 1018 | 1055 |
| 1019 // static | 1056 // static |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1111 return; | 1148 return; |
| 1112 } | 1149 } |
| 1113 AutoLock auto_lock(global_->lock_); | 1150 AutoLock auto_lock(global_->lock_); |
| 1114 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1151 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
| 1115 trial->AddRef(); | 1152 trial->AddRef(); |
| 1116 trial->SetTrialRegistered(); | 1153 trial->SetTrialRegistered(); |
| 1117 global_->registered_[trial->trial_name()] = trial; | 1154 global_->registered_[trial->trial_name()] = trial; |
| 1118 } | 1155 } |
| 1119 | 1156 |
| 1120 } // namespace base | 1157 } // namespace base |
| OLD | NEW |