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" |
| (...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 const std::string& trial_name, | |
| 191 const 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)) { | |
| 203 CHECK(false); | |
| 204 } | |
| 205 | |
| 206 std::string existing_trial_name = trial_name_to_check.as_string(); | |
|
brucedawson
2016/11/21 22:07:00
Why copy these to std::string objects? This requir
lawrencewu
2016/11/22 15:17:54
I think it's more readable this way, but yeah, sin
brucedawson
2016/11/22 17:55:24
Thanks. Given the separate thread going on about t
| |
| 207 std::string existing_group_name = group_name_to_check.as_string(); | |
| 208 if (existing_trial_name == trial_name) { | |
| 209 constexpr size_t buf_size = 100; | |
| 210 | |
| 211 char trial_name_c_str[buf_size]; | |
| 212 char group_name_c_str[buf_size]; | |
| 213 char existing_group_name_c_str[buf_size]; | |
| 214 | |
| 215 strlcpy(trial_name_c_str, trial_name.c_str(), buf_size); | |
| 216 strlcpy(group_name_c_str, group_name.c_str(), buf_size); | |
| 217 strlcpy(existing_group_name_c_str, existing_group_name.c_str(), buf_size); | |
| 218 | |
| 219 debug::Alias(trial_name_c_str); | |
| 220 debug::Alias(existing_group_name_c_str); | |
| 221 debug::Alias(group_name_c_str); | |
|
brucedawson
2016/11/21 22:07:00
For consistency and to minimize confusion keep the
lawrencewu
2016/11/22 15:17:54
Done.
| |
| 222 CHECK_EQ(existing_group_name, group_name); | |
| 223 } | |
| 224 } | |
| 225 } | |
| 226 | |
| 184 #if defined(OS_WIN) | 227 #if defined(OS_WIN) |
| 185 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { | 228 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { |
| 186 HANDLE src = allocator->shared_memory()->handle().GetHandle(); | 229 HANDLE src = allocator->shared_memory()->handle().GetHandle(); |
| 187 ProcessHandle process = GetCurrentProcess(); | 230 ProcessHandle process = GetCurrentProcess(); |
| 188 DWORD access = SECTION_MAP_READ | SECTION_QUERY; | 231 DWORD access = SECTION_MAP_READ | SECTION_QUERY; |
| 189 HANDLE dst; | 232 HANDLE dst; |
| 190 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) | 233 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) |
| 191 return nullptr; | 234 return nullptr; |
| 192 return dst; | 235 return dst; |
| 193 } | 236 } |
| (...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 850 return false; | 893 return false; |
| 851 | 894 |
| 852 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take | 895 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take |
| 853 // StringPieces. | 896 // StringPieces. |
| 854 FieldTrial* trial = | 897 FieldTrial* trial = |
| 855 CreateFieldTrial(trial_name.as_string(), group_name.as_string()); | 898 CreateFieldTrial(trial_name.as_string(), group_name.as_string()); |
| 856 | 899 |
| 857 // If we failed to create the field trial, crash with debug info. | 900 // If we failed to create the field trial, crash with debug info. |
| 858 // TODO(665129): Remove this when the crash is resolved. | 901 // TODO(665129): Remove this when the crash is resolved. |
| 859 if (!trial) { | 902 if (!trial) { |
| 903 constexpr size_t buf_size = 100; | |
| 904 char trial_name_c_str[buf_size] = {0}; | |
| 905 char group_name_c_str[buf_size] = {0}; | |
| 906 char existing_group_name_c_str[buf_size] = {0}; | |
| 907 | |
| 908 // Copy the names over to the stack. | |
| 860 std::string trial_name_string = trial_name.as_string(); | 909 std::string trial_name_string = trial_name.as_string(); |
| 910 strlcpy(trial_name_c_str, trial_name_string.c_str(), buf_size); | |
| 861 std::string group_name_string = group_name.as_string(); | 911 std::string group_name_string = group_name.as_string(); |
| 912 strlcpy(group_name_c_str, group_name_string.c_str(), buf_size); | |
| 913 | |
| 914 // Alias the trial and group name. | |
| 915 debug::Alias(trial_name_c_str); | |
| 916 debug::Alias(group_name_c_str); | |
| 917 | |
| 918 // Copy and alias the existing field trial name, if there is one. | |
| 862 FieldTrial* existing_field_trial = | 919 FieldTrial* existing_field_trial = |
| 863 FieldTrialList::Find(trial_name_string); | 920 FieldTrialList::Find(trial_name_string); |
| 864 if (existing_field_trial) | 921 if (existing_field_trial) { |
| 865 debug::Alias(existing_field_trial->group_name_internal().c_str()); | 922 std::string existing_group_name_string = |
| 866 debug::Alias(trial_name_string.c_str()); | 923 existing_field_trial->group_name_internal(); |
| 867 debug::Alias(group_name_string.c_str()); | 924 strlcpy(existing_group_name_c_str, group_name_string.c_str(), buf_size); |
| 925 debug::Alias(existing_group_name_c_str); | |
| 926 } | |
| 868 CHECK(!trial_name_string.empty()); | 927 CHECK(!trial_name_string.empty()); |
| 869 CHECK(!group_name_string.empty()); | 928 CHECK(!group_name_string.empty()); |
| 870 CHECK_EQ(existing_field_trial->group_name_internal(), | 929 CHECK_EQ(existing_field_trial->group_name_internal(), |
| 871 group_name.as_string()); | 930 group_name.as_string()); |
| 872 return false; | 931 return false; |
| 873 } | 932 } |
| 874 | 933 |
| 875 trial->ref_ = ref; | 934 trial->ref_ = ref; |
| 876 if (entry->activated) { | 935 if (entry->activated) { |
| 877 // Call |group()| to mark the trial as "used" and notify observers, if | 936 // Call |group()| to mark the trial as "used" and notify observers, if |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 921 | 980 |
| 922 // Don't do anything if the allocator hasn't been instantiated yet. | 981 // Don't do anything if the allocator hasn't been instantiated yet. |
| 923 if (allocator == nullptr) | 982 if (allocator == nullptr) |
| 924 return; | 983 return; |
| 925 | 984 |
| 926 // Or if the allocator is read only, which means we are in a child process and | 985 // Or if the allocator is read only, which means we are in a child process and |
| 927 // shouldn't be writing to it. | 986 // shouldn't be writing to it. |
| 928 if (allocator->IsReadonly()) | 987 if (allocator->IsReadonly()) |
| 929 return; | 988 return; |
| 930 | 989 |
| 990 // TODO(665129): Remove this code once the bug has been fixed. | |
| 991 CheckAllocatorForTrial(allocator, field_trial->trial_name(), | |
| 992 field_trial->group_name_internal()); | |
| 993 | |
| 931 FieldTrial::State trial_state; | 994 FieldTrial::State trial_state; |
| 932 if (!field_trial->GetStateWhileLocked(&trial_state)) | 995 if (!field_trial->GetStateWhileLocked(&trial_state)) |
| 933 return; | 996 return; |
| 934 | 997 |
| 935 // Or if we've already added it. We must check after GetState since it can | 998 // Or if we've already added it. We must check after GetState since it can |
| 936 // also add to the allocator. | 999 // also add to the allocator. |
| 937 if (field_trial->ref_) | 1000 if (field_trial->ref_) |
| 938 return; | 1001 return; |
| 939 | 1002 |
| 940 Pickle pickle; | 1003 Pickle pickle; |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1010 return; | 1073 return; |
| 1011 } | 1074 } |
| 1012 AutoLock auto_lock(global_->lock_); | 1075 AutoLock auto_lock(global_->lock_); |
| 1013 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1076 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
| 1014 trial->AddRef(); | 1077 trial->AddRef(); |
| 1015 trial->SetTrialRegistered(); | 1078 trial->SetTrialRegistered(); |
| 1016 global_->registered_[trial->trial_name()] = trial; | 1079 global_->registered_[trial->trial_name()] = trial; |
| 1017 } | 1080 } |
| 1018 | 1081 |
| 1019 } // namespace base | 1082 } // namespace base |
| OLD | NEW |