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" |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
174 | 174 |
175 void AddForceFieldTrialsFlag(CommandLine* cmd_line) { | 175 void AddForceFieldTrialsFlag(CommandLine* cmd_line) { |
176 std::string field_trial_states; | 176 std::string field_trial_states; |
177 FieldTrialList::AllStatesToString(&field_trial_states); | 177 FieldTrialList::AllStatesToString(&field_trial_states); |
178 if (!field_trial_states.empty()) { | 178 if (!field_trial_states.empty()) { |
179 cmd_line->AppendSwitchASCII(switches::kForceFieldTrials, | 179 cmd_line->AppendSwitchASCII(switches::kForceFieldTrials, |
180 field_trial_states); | 180 field_trial_states); |
181 } | 181 } |
182 } | 182 } |
183 | 183 |
184 // In order to debug the crash where two field trials with the same name but | |
185 // different groups get added to the allocator, let's try to get the stack | |
186 // frame where the second duplicate gets added here as well as the trial/group | |
187 // names by going through the allocator and checking if a trial with the same | |
188 // name already exists. | |
189 void CheckAllocatorForTrial(FieldTrialList::FieldTrialAllocator* allocator, | |
190 std::string trial_name, | |
Alexei Svitkine (slow)
2016/11/21 20:11:33
Nit: const&
Same for the next param.
lawrencewu
2016/11/21 20:41:23
Done.
| |
191 std::string group_name) { | |
192 FieldTrialList::FieldTrialAllocator::Iterator iter(allocator); | |
193 FieldTrial::FieldTrialRef ref; | |
194 while ((ref = iter.GetNextOfType(kFieldTrialType)) != | |
195 FieldTrialList::FieldTrialAllocator::kReferenceNull) { | |
196 const FieldTrialEntry* entry = | |
197 allocator->GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType); | |
198 | |
199 StringPiece trial_name_to_check; | |
200 StringPiece group_name_to_check; | |
201 if (!entry->GetTrialAndGroupName(&trial_name_to_check, | |
202 &group_name_to_check)) | |
Alexei Svitkine (slow)
2016/11/21 20:11:33
Nit: {}'s
lawrencewu
2016/11/21 20:41:23
Done.
| |
203 CHECK(false); | |
204 | |
205 std::string existing_trial_name = trial_name_to_check.as_string(); | |
206 std::string existing_group_name = group_name_to_check.as_string(); | |
207 if (existing_trial_name == trial_name) { | |
208 constexpr size_t buf_size = 100; | |
209 | |
210 char trial_name_c_str[buf_size]; | |
211 char group_name_c_str[buf_size]; | |
212 char existing_group_name_c_str[buf_size]; | |
213 | |
214 strlcpy(trial_name_c_str, trial_name.c_str(), buf_size); | |
215 strlcpy(group_name_c_str, group_name.c_str(), buf_size); | |
216 strlcpy(existing_group_name_c_str, existing_group_name.c_str(), buf_size); | |
217 | |
218 debug::Alias(trial_name_c_str); | |
219 debug::Alias(existing_group_name_c_str); | |
220 debug::Alias(group_name_c_str); | |
221 CHECK_EQ(existing_group_name, group_name); | |
222 } | |
223 } | |
224 } | |
225 | |
184 #if defined(OS_WIN) | 226 #if defined(OS_WIN) |
185 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { | 227 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { |
186 HANDLE src = allocator->shared_memory()->handle().GetHandle(); | 228 HANDLE src = allocator->shared_memory()->handle().GetHandle(); |
187 ProcessHandle process = GetCurrentProcess(); | 229 ProcessHandle process = GetCurrentProcess(); |
188 DWORD access = SECTION_MAP_READ | SECTION_QUERY; | 230 DWORD access = SECTION_MAP_READ | SECTION_QUERY; |
189 HANDLE dst; | 231 HANDLE dst; |
190 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) | 232 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) |
191 return nullptr; | 233 return nullptr; |
192 return dst; | 234 return dst; |
193 } | 235 } |
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
850 return false; | 892 return false; |
851 | 893 |
852 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take | 894 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take |
853 // StringPieces. | 895 // StringPieces. |
854 FieldTrial* trial = | 896 FieldTrial* trial = |
855 CreateFieldTrial(trial_name.as_string(), group_name.as_string()); | 897 CreateFieldTrial(trial_name.as_string(), group_name.as_string()); |
856 | 898 |
857 // If we failed to create the field trial, crash with debug info. | 899 // If we failed to create the field trial, crash with debug info. |
858 // TODO(665129): Remove this when the crash is resolved. | 900 // TODO(665129): Remove this when the crash is resolved. |
859 if (!trial) { | 901 if (!trial) { |
902 constexpr size_t buf_size = 100; | |
903 char trial_name_c_str[buf_size] = {0}; | |
904 char group_name_c_str[buf_size] = {0}; | |
905 char existing_group_name_c_str[buf_size] = {0}; | |
906 | |
907 // Copy the names over to the stack. | |
860 std::string trial_name_string = trial_name.as_string(); | 908 std::string trial_name_string = trial_name.as_string(); |
909 strlcpy(trial_name_c_str, trial_name_string.c_str(), buf_size); | |
861 std::string group_name_string = group_name.as_string(); | 910 std::string group_name_string = group_name.as_string(); |
911 strlcpy(group_name_c_str, group_name_string.c_str(), buf_size); | |
912 | |
913 // Alias the trial and group name. | |
914 debug::Alias(trial_name_c_str); | |
915 debug::Alias(group_name_c_str); | |
916 | |
917 // Copy and alias the existing field trial name, if there is one. | |
862 FieldTrial* existing_field_trial = | 918 FieldTrial* existing_field_trial = |
863 FieldTrialList::Find(trial_name_string); | 919 FieldTrialList::Find(trial_name_string); |
864 if (existing_field_trial) | 920 if (existing_field_trial) { |
865 debug::Alias(existing_field_trial->group_name_internal().c_str()); | 921 std::string existing_group_name_string = |
866 debug::Alias(trial_name_string.c_str()); | 922 existing_field_trial->group_name_internal(); |
867 debug::Alias(group_name_string.c_str()); | 923 strlcpy(existing_group_name_c_str, group_name_string.c_str(), buf_size); |
924 debug::Alias(existing_group_name_c_str); | |
925 } | |
868 CHECK(!trial_name_string.empty()); | 926 CHECK(!trial_name_string.empty()); |
869 CHECK(!group_name_string.empty()); | 927 CHECK(!group_name_string.empty()); |
870 CHECK_EQ(existing_field_trial->group_name_internal(), | 928 CHECK_EQ(existing_field_trial->group_name_internal(), |
871 group_name.as_string()); | 929 group_name.as_string()); |
872 return false; | 930 return false; |
873 } | 931 } |
874 | 932 |
875 trial->ref_ = ref; | 933 trial->ref_ = ref; |
876 if (entry->activated) { | 934 if (entry->activated) { |
877 // Call |group()| to mark the trial as "used" and notify observers, if | 935 // Call |group()| to mark the trial as "used" and notify observers, if |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
912 global_->readonly_allocator_handle_ = | 970 global_->readonly_allocator_handle_ = |
913 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); | 971 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); |
914 #endif | 972 #endif |
915 } | 973 } |
916 #endif | 974 #endif |
917 | 975 |
918 // static | 976 // static |
919 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { | 977 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { |
920 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); | 978 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); |
921 | 979 |
980 // TODO(665129): Remove this code once the bug has been fixed. | |
981 CheckAllocatorForTrial(allocator, field_trial->trial_name(), | |
982 field_trial->group_name_internal()); | |
983 | |
922 // Don't do anything if the allocator hasn't been instantiated yet. | 984 // Don't do anything if the allocator hasn't been instantiated yet. |
923 if (allocator == nullptr) | 985 if (allocator == nullptr) |
924 return; | 986 return; |
925 | 987 |
926 // Or if the allocator is read only, which means we are in a child process and | 988 // Or if the allocator is read only, which means we are in a child process and |
927 // shouldn't be writing to it. | 989 // shouldn't be writing to it. |
928 if (allocator->IsReadonly()) | 990 if (allocator->IsReadonly()) |
929 return; | 991 return; |
930 | 992 |
931 FieldTrial::State trial_state; | 993 FieldTrial::State trial_state; |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1010 return; | 1072 return; |
1011 } | 1073 } |
1012 AutoLock auto_lock(global_->lock_); | 1074 AutoLock auto_lock(global_->lock_); |
1013 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1075 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
1014 trial->AddRef(); | 1076 trial->AddRef(); |
1015 trial->SetTrialRegistered(); | 1077 trial->SetTrialRegistered(); |
1016 global_->registered_[trial->trial_name()] = trial; | 1078 global_->registered_[trial->trial_name()] = trial; |
1017 } | 1079 } |
1018 | 1080 |
1019 } // namespace base | 1081 } // namespace base |
OLD | NEW |