| 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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 44 const char kAllocatorName[] = "FieldTrialAllocator"; | 44 const char kAllocatorName[] = "FieldTrialAllocator"; |
| 45 const uint32_t kFieldTrialType = 0xABA17E13 + 1; // SHA1(FieldTrialEntry) v1 | 45 const uint32_t kFieldTrialType = 0xABA17E13 + 1; // SHA1(FieldTrialEntry) v1 |
| 46 #if !defined(OS_NACL) | 46 #if !defined(OS_NACL) |
| 47 const size_t kFieldTrialAllocationSize = 4 << 10; // 4 KiB = one page | 47 const size_t kFieldTrialAllocationSize = 4 << 10; // 4 KiB = one page |
| 48 #endif | 48 #endif |
| 49 | 49 |
| 50 // We create one FieldTrialEntry per field trial in shared memory, via | 50 // We create one FieldTrialEntry per field trial in shared memory, via |
| 51 // AddToAllocatorWhileLocked. The FieldTrialEntry is followed by a base::Pickle | 51 // AddToAllocatorWhileLocked. The FieldTrialEntry is followed by a base::Pickle |
| 52 // object that we unpickle and read from. | 52 // object that we unpickle and read from. |
| 53 struct FieldTrialEntry { | 53 struct FieldTrialEntry { |
| 54 // Whether or not this field trial is activated. |
| 54 bool activated; | 55 bool activated; |
| 55 | 56 |
| 56 // Size of the pickled structure, NOT the total size of this entry. | 57 // Size of the pickled structure, NOT the total size of this entry. |
| 57 uint32_t size; | 58 uint32_t size; |
| 58 | 59 |
| 60 // Returns an iterator over the data used for getting names and params. |
| 61 PickleIterator GetPickleIterator() const { |
| 62 char* src = reinterpret_cast<char*>(const_cast<FieldTrialEntry*>(this)) + |
| 63 sizeof(FieldTrialEntry); |
| 64 |
| 65 Pickle pickle(src, size); |
| 66 return PickleIterator(pickle); |
| 67 } |
| 68 |
| 69 // Takes the iterator and writes out the first two items into |trial_name| and |
| 70 // |group_name|. |
| 71 bool ReadStringPair(PickleIterator iter, |
| 72 StringPiece* trial_name, |
| 73 StringPiece* group_name) const { |
| 74 if (!iter.ReadStringPiece(trial_name)) |
| 75 return false; |
| 76 if (!iter.ReadStringPiece(group_name)) |
| 77 return false; |
| 78 return true; |
| 79 } |
| 80 |
| 59 // Calling this is only valid when the entry is initialized. That is, it | 81 // Calling this is only valid when the entry is initialized. That is, it |
| 60 // resides in shared memory and has a pickle containing the trial name and | 82 // resides in shared memory and has a pickle containing the trial name and |
| 61 // group name following it. | 83 // group name following it. |
| 62 bool GetTrialAndGroupName(StringPiece* trial_name, | 84 bool GetTrialAndGroupName(StringPiece* trial_name, |
| 63 StringPiece* group_name) const { | 85 StringPiece* group_name) const { |
| 64 char* src = reinterpret_cast<char*>(const_cast<FieldTrialEntry*>(this)) + | 86 PickleIterator iter = GetPickleIterator(); |
| 65 sizeof(FieldTrialEntry); | 87 return ReadStringPair(iter, trial_name, group_name); |
| 88 } |
| 66 | 89 |
| 67 Pickle pickle(src, size); | 90 bool GetParams(FieldTrialParamAssociator::FieldTrialParams* params) const { |
| 68 PickleIterator pickle_iter(pickle); | 91 PickleIterator iter = GetPickleIterator(); |
| 92 StringPiece tmp; |
| 93 if (!ReadStringPair(iter, &tmp, &tmp)) |
| 94 return false; |
| 69 | 95 |
| 70 if (!pickle_iter.ReadStringPiece(trial_name)) | 96 while (true) { |
| 71 return false; | 97 StringPiece key; |
| 72 if (!pickle_iter.ReadStringPiece(group_name)) | 98 StringPiece value; |
| 73 return false; | 99 if (!iter.ReadStringPiece(&key)) |
| 74 return true; | 100 return true; // No more params to read. |
| 101 if (!iter.ReadStringPiece(&value)) |
| 102 return false; |
| 103 (*params)[key.as_string()] = value.as_string(); |
| 104 } |
| 105 |
| 106 NOTREACHED() << "Hit field trial param limit"; |
| 107 return false; |
| 75 } | 108 } |
| 76 }; | 109 }; |
| 77 | 110 |
| 78 // Created a time value based on |year|, |month| and |day_of_month| parameters. | 111 // Created a time value based on |year|, |month| and |day_of_month| parameters. |
| 79 Time CreateTimeFromParams(int year, int month, int day_of_month) { | 112 Time CreateTimeFromParams(int year, int month, int day_of_month) { |
| 80 DCHECK_GT(year, 1970); | 113 DCHECK_GT(year, 1970); |
| 81 DCHECK_GT(month, 0); | 114 DCHECK_GT(month, 0); |
| 82 DCHECK_LT(month, 13); | 115 DCHECK_LT(month, 13); |
| 83 DCHECK_GT(day_of_month, 0); | 116 DCHECK_GT(day_of_month, 0); |
| 84 DCHECK_LT(day_of_month, 32); | 117 DCHECK_LT(day_of_month, 32); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 HANDLE src = allocator->shared_memory()->handle().GetHandle(); | 207 HANDLE src = allocator->shared_memory()->handle().GetHandle(); |
| 175 ProcessHandle process = GetCurrentProcess(); | 208 ProcessHandle process = GetCurrentProcess(); |
| 176 DWORD access = SECTION_MAP_READ | SECTION_QUERY; | 209 DWORD access = SECTION_MAP_READ | SECTION_QUERY; |
| 177 HANDLE dst; | 210 HANDLE dst; |
| 178 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) | 211 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) |
| 179 return nullptr; | 212 return nullptr; |
| 180 return dst; | 213 return dst; |
| 181 } | 214 } |
| 182 #endif | 215 #endif |
| 183 | 216 |
| 217 bool PickleFieldTrialState(const FieldTrial::State& trial_state, |
| 218 Pickle* pickle) { |
| 219 pickle->WriteString(trial_state.trial_name); |
| 220 pickle->WriteString(trial_state.group_name); |
| 221 |
| 222 std::map<std::string, std::string> params; |
| 223 if (!FieldTrialParamAssociator::GetInstance() |
| 224 ->GetFieldTrialParamsWithGroupName( |
| 225 trial_state.trial_name.as_string(), |
| 226 trial_state.group_name.as_string(), ¶ms)) { |
| 227 return false; |
| 228 } |
| 229 |
| 230 for (const auto& param : params) { |
| 231 pickle->WriteString(StringPiece(param.first)); |
| 232 pickle->WriteString(StringPiece(param.second)); |
| 233 } |
| 234 return true; |
| 235 } |
| 236 |
| 184 } // namespace | 237 } // namespace |
| 185 | 238 |
| 186 // statics | 239 // statics |
| 187 const int FieldTrial::kNotFinalized = -1; | 240 const int FieldTrial::kNotFinalized = -1; |
| 188 const int FieldTrial::kDefaultGroupNumber = 0; | 241 const int FieldTrial::kDefaultGroupNumber = 0; |
| 189 bool FieldTrial::enable_benchmarking_ = false; | 242 bool FieldTrial::enable_benchmarking_ = false; |
| 190 | 243 |
| 191 int FieldTrialList::kNoExpirationYear = 0; | 244 int FieldTrialList::kNoExpirationYear = 0; |
| 192 | 245 |
| 193 //------------------------------------------------------------------------------ | 246 //------------------------------------------------------------------------------ |
| (...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 520 | 573 |
| 521 // static | 574 // static |
| 522 std::string FieldTrialList::FindFullName(const std::string& trial_name) { | 575 std::string FieldTrialList::FindFullName(const std::string& trial_name) { |
| 523 FieldTrial* field_trial = Find(trial_name); | 576 FieldTrial* field_trial = Find(trial_name); |
| 524 if (field_trial) | 577 if (field_trial) |
| 525 return field_trial->group_name(); | 578 return field_trial->group_name(); |
| 526 return std::string(); | 579 return std::string(); |
| 527 } | 580 } |
| 528 | 581 |
| 529 // static | 582 // static |
| 583 bool FieldTrialList::FindParams( |
| 584 const std::string& trial_name, |
| 585 FieldTrialParamAssociator::FieldTrialParams* params) { |
| 586 // Check that the allocator exists (it may not exist on Linux or macOS). This |
| 587 // shouldn't ever happen on Windows, as child processes should get an |
| 588 // allocator during initialization, and browser processes won't hit this |
| 589 // function since it has the mapping in FieldTrialParamAssociator. |
| 590 SharedPersistentMemoryAllocator* allocator = |
| 591 global_->field_trial_allocator_.get(); |
| 592 if (allocator == nullptr) |
| 593 return false; |
| 594 |
| 595 // Get the field trial's corresponding reference in shared memory. This |
| 596 // shouldn't happen for on Windows the same reasons above. |
| 597 FieldTrial* field_trial = Find(trial_name); |
| 598 if (field_trial->ref_ == SharedPersistentMemoryAllocator::kReferenceNull) |
| 599 return false; |
| 600 |
| 601 FieldTrialEntry* entry = allocator->GetAsObject<FieldTrialEntry>( |
| 602 field_trial->ref_, kFieldTrialType); |
| 603 return entry->GetParams(params); |
| 604 } |
| 605 |
| 606 // static |
| 530 bool FieldTrialList::TrialExists(const std::string& trial_name) { | 607 bool FieldTrialList::TrialExists(const std::string& trial_name) { |
| 531 return Find(trial_name) != NULL; | 608 return Find(trial_name) != NULL; |
| 532 } | 609 } |
| 533 | 610 |
| 534 // static | 611 // static |
| 535 bool FieldTrialList::IsTrialActive(const std::string& trial_name) { | 612 bool FieldTrialList::IsTrialActive(const std::string& trial_name) { |
| 536 FieldTrial* field_trial = Find(trial_name); | 613 FieldTrial* field_trial = Find(trial_name); |
| 537 FieldTrial::ActiveGroup active_group; | 614 FieldTrial::ActiveGroup active_group; |
| 538 return field_trial && field_trial->GetActiveGroup(&active_group); | 615 return field_trial && field_trial->GetActiveGroup(&active_group); |
| 539 } | 616 } |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 816 size_t FieldTrialList::GetFieldTrialCount() { | 893 size_t FieldTrialList::GetFieldTrialCount() { |
| 817 if (!global_) | 894 if (!global_) |
| 818 return 0; | 895 return 0; |
| 819 AutoLock auto_lock(global_->lock_); | 896 AutoLock auto_lock(global_->lock_); |
| 820 return global_->registered_.size(); | 897 return global_->registered_.size(); |
| 821 } | 898 } |
| 822 | 899 |
| 823 // static | 900 // static |
| 824 void FieldTrialList::CreateTrialsFromSharedMemory( | 901 void FieldTrialList::CreateTrialsFromSharedMemory( |
| 825 std::unique_ptr<SharedMemory> shm) { | 902 std::unique_ptr<SharedMemory> shm) { |
| 826 const SharedPersistentMemoryAllocator shalloc(std::move(shm), 0, | 903 global_->field_trial_allocator_.reset(new SharedPersistentMemoryAllocator( |
| 827 kAllocatorName, true); | 904 std::move(shm), 0, kAllocatorName, true)); |
| 828 PersistentMemoryAllocator::Iterator mem_iter(&shalloc); | 905 SharedPersistentMemoryAllocator* shalloc = |
| 906 global_->field_trial_allocator_.get(); |
| 907 PersistentMemoryAllocator::Iterator mem_iter(shalloc); |
| 829 | 908 |
| 830 SharedPersistentMemoryAllocator::Reference ref; | 909 SharedPersistentMemoryAllocator::Reference ref; |
| 831 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) != | 910 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) != |
| 832 SharedPersistentMemoryAllocator::kReferenceNull) { | 911 SharedPersistentMemoryAllocator::kReferenceNull) { |
| 833 const FieldTrialEntry* entry = | 912 const FieldTrialEntry* entry = |
| 834 shalloc.GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType); | 913 shalloc->GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType); |
| 835 | 914 |
| 836 StringPiece trial_name; | 915 StringPiece trial_name; |
| 837 StringPiece group_name; | 916 StringPiece group_name; |
| 838 if (!entry->GetTrialAndGroupName(&trial_name, &group_name)) { | 917 if (!entry->GetTrialAndGroupName(&trial_name, &group_name)) { |
| 839 NOTREACHED(); | 918 NOTREACHED(); |
| 840 continue; | 919 continue; |
| 841 } | 920 } |
| 842 | 921 |
| 843 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take | 922 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take |
| 844 // StringPieces. | 923 // StringPieces. |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 897 | 976 |
| 898 // Or if we've already added it. | 977 // Or if we've already added it. |
| 899 if (field_trial->ref_ != SharedPersistentMemoryAllocator::kReferenceNull) | 978 if (field_trial->ref_ != SharedPersistentMemoryAllocator::kReferenceNull) |
| 900 return; | 979 return; |
| 901 | 980 |
| 902 FieldTrial::State trial_state; | 981 FieldTrial::State trial_state; |
| 903 if (!field_trial->GetState(&trial_state)) | 982 if (!field_trial->GetState(&trial_state)) |
| 904 return; | 983 return; |
| 905 | 984 |
| 906 Pickle pickle; | 985 Pickle pickle; |
| 907 pickle.WriteString(trial_state.trial_name); | 986 if (!PickleFieldTrialState(trial_state, &pickle)) |
| 908 pickle.WriteString(trial_state.group_name); | 987 return; |
| 909 | 988 |
| 910 size_t total_size = sizeof(FieldTrialEntry) + pickle.size(); | 989 size_t total_size = sizeof(FieldTrialEntry) + pickle.size(); |
| 911 SharedPersistentMemoryAllocator::Reference ref = | 990 SharedPersistentMemoryAllocator::Reference ref = |
| 912 allocator->Allocate(total_size, kFieldTrialType); | 991 allocator->Allocate(total_size, kFieldTrialType); |
| 913 if (ref == SharedPersistentMemoryAllocator::kReferenceNull) | 992 if (ref == SharedPersistentMemoryAllocator::kReferenceNull) |
| 914 return; | 993 return; |
| 915 | 994 |
| 916 FieldTrialEntry* entry = | 995 FieldTrialEntry* entry = |
| 917 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType); | 996 allocator->GetAsObject<FieldTrialEntry>(ref, kFieldTrialType); |
| 918 entry->activated = trial_state.activated; | 997 entry->activated = trial_state.activated; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 972 return; | 1051 return; |
| 973 } | 1052 } |
| 974 AutoLock auto_lock(global_->lock_); | 1053 AutoLock auto_lock(global_->lock_); |
| 975 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1054 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
| 976 trial->AddRef(); | 1055 trial->AddRef(); |
| 977 trial->SetTrialRegistered(); | 1056 trial->SetTrialRegistered(); |
| 978 global_->registered_[trial->trial_name()] = trial; | 1057 global_->registered_[trial->trial_name()] = trial; |
| 979 } | 1058 } |
| 980 | 1059 |
| 981 } // namespace base | 1060 } // namespace base |
| OLD | NEW |