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 #if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_MACOSX) && \ | |
| 6 !defined(OS_ANDROID) | |
| 7 #define POSIX_WITH_ZYGOTE 1 | |
| 8 #endif | |
|
Alexei Svitkine (slow)
2016/11/24 17:44:34
Not At the top of the file - put it after all the
lawrencewu
2016/11/24 18:16:13
Done.
| |
| 9 | |
| 5 #include "base/metrics/field_trial.h" | 10 #include "base/metrics/field_trial.h" |
| 6 | 11 |
| 7 #include <algorithm> | 12 #include <algorithm> |
| 8 #include <utility> | 13 #include <utility> |
| 9 | 14 |
| 10 #include "base/base_switches.h" | 15 #include "base/base_switches.h" |
| 11 #include "base/build_time.h" | 16 #include "base/build_time.h" |
| 12 #include "base/command_line.h" | 17 #include "base/command_line.h" |
| 13 #include "base/debug/alias.h" | 18 #include "base/debug/alias.h" |
| 14 #include "base/feature_list.h" | 19 #include "base/feature_list.h" |
| 15 #include "base/logging.h" | 20 #include "base/logging.h" |
| 16 #include "base/pickle.h" | 21 #include "base/pickle.h" |
| 17 #include "base/process/memory.h" | 22 #include "base/process/memory.h" |
| 18 #include "base/rand_util.h" | 23 #include "base/rand_util.h" |
| 19 #include "base/strings/string_number_conversions.h" | 24 #include "base/strings/string_number_conversions.h" |
| 20 #include "base/strings/string_util.h" | 25 #include "base/strings/string_util.h" |
| 21 #include "base/strings/stringprintf.h" | 26 #include "base/strings/stringprintf.h" |
| 22 #include "base/strings/utf_string_conversions.h" | 27 #include "base/strings/utf_string_conversions.h" |
| 23 | 28 |
| 29 #if defined(POSIX_WITH_ZYGOTE) | |
| 30 #include "base/posix/global_descriptors.h" | |
| 31 #endif | |
| 32 | |
| 24 namespace base { | 33 namespace base { |
| 25 | 34 |
| 26 namespace { | 35 namespace { |
| 27 | 36 |
| 28 // Define a separator character to use when creating a persistent form of an | 37 // Define a separator character to use when creating a persistent form of an |
| 29 // instance. This is intended for use as a command line argument, passed to a | 38 // instance. This is intended for use as a command line argument, passed to a |
| 30 // second process to mimic our state (i.e., provide the same group name). | 39 // second process to mimic our state (i.e., provide the same group name). |
| 31 const char kPersistentStringSeparator = '/'; // Currently a slash. | 40 const char kPersistentStringSeparator = '/'; // Currently a slash. |
| 32 | 41 |
| 33 // Define a marker character to be used as a prefix to a trial name on the | 42 // Define a marker character to be used as a prefix to a trial name on the |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 231 HANDLE src = allocator->shared_memory()->handle().GetHandle(); | 240 HANDLE src = allocator->shared_memory()->handle().GetHandle(); |
| 232 ProcessHandle process = GetCurrentProcess(); | 241 ProcessHandle process = GetCurrentProcess(); |
| 233 DWORD access = SECTION_MAP_READ | SECTION_QUERY; | 242 DWORD access = SECTION_MAP_READ | SECTION_QUERY; |
| 234 HANDLE dst; | 243 HANDLE dst; |
| 235 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) | 244 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) |
| 236 return nullptr; | 245 return nullptr; |
| 237 return dst; | 246 return dst; |
| 238 } | 247 } |
| 239 #endif | 248 #endif |
| 240 | 249 |
| 250 #if defined(POSIX_WITH_ZYGOTE) | |
| 251 int CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { | |
| 252 SharedMemoryHandle new_handle; | |
| 253 allocator->shared_memory()->ShareReadOnlyToProcess(GetCurrentProcessHandle(), | |
| 254 &new_handle); | |
| 255 return SharedMemory::GetFdFromSharedMemoryHandle(new_handle); | |
| 256 } | |
| 257 #endif | |
| 258 | |
| 241 } // namespace | 259 } // namespace |
| 242 | 260 |
| 243 // statics | 261 // statics |
| 244 const int FieldTrial::kNotFinalized = -1; | 262 const int FieldTrial::kNotFinalized = -1; |
| 245 const int FieldTrial::kDefaultGroupNumber = 0; | 263 const int FieldTrial::kDefaultGroupNumber = 0; |
| 246 bool FieldTrial::enable_benchmarking_ = false; | 264 bool FieldTrial::enable_benchmarking_ = false; |
| 247 | 265 |
| 248 int FieldTrialList::kNoExpirationYear = 0; | 266 int FieldTrialList::kNoExpirationYear = 0; |
| 249 | 267 |
| 250 //------------------------------------------------------------------------------ | 268 //------------------------------------------------------------------------------ |
| (...skipping 482 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 733 } | 751 } |
| 734 return true; | 752 return true; |
| 735 } | 753 } |
| 736 | 754 |
| 737 // static | 755 // static |
| 738 void FieldTrialList::CreateTrialsFromCommandLine( | 756 void FieldTrialList::CreateTrialsFromCommandLine( |
| 739 const CommandLine& cmd_line, | 757 const CommandLine& cmd_line, |
| 740 const char* field_trial_handle_switch) { | 758 const char* field_trial_handle_switch) { |
| 741 global_->create_trials_from_command_line_called_ = true; | 759 global_->create_trials_from_command_line_called_ = true; |
| 742 | 760 |
| 743 #if defined(OS_WIN) && !defined(OS_NACL) | |
| 744 if (cmd_line.HasSwitch(field_trial_handle_switch)) { | 761 if (cmd_line.HasSwitch(field_trial_handle_switch)) { |
| 745 std::string arg = cmd_line.GetSwitchValueASCII(field_trial_handle_switch); | 762 std::string handle_switch = |
| 746 int field_trial_handle = std::stoi(arg); | 763 cmd_line.GetSwitchValueASCII(field_trial_handle_switch); |
| 747 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle); | 764 bool result = CreateTrialsFromHandleSwitch(handle_switch); |
| 748 bool result = CreateTrialsFromWindowsHandle(handle); | |
| 749 DCHECK(result); | 765 DCHECK(result); |
| 750 } | 766 } |
| 751 #endif | |
| 752 | 767 |
| 753 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { | 768 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { |
| 754 bool result = FieldTrialList::CreateTrialsFromString( | 769 bool result = FieldTrialList::CreateTrialsFromString( |
| 755 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), | 770 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), |
| 756 std::set<std::string>()); | 771 std::set<std::string>()); |
| 757 DCHECK(result); | 772 DCHECK(result); |
| 758 } | 773 } |
| 759 } | 774 } |
| 760 | 775 |
| 761 #if defined(OS_WIN) | 776 #if defined(OS_WIN) |
| 762 // static | 777 // static |
| 763 void FieldTrialList::AppendFieldTrialHandleIfNeeded( | 778 void FieldTrialList::AppendFieldTrialHandleIfNeeded( |
| 764 HandlesToInheritVector* handles) { | 779 HandlesToInheritVector* handles) { |
| 765 if (!global_) | 780 if (!global_) |
| 766 return; | 781 return; |
| 767 if (kUseSharedMemoryForFieldTrials) { | 782 if (kUseSharedMemoryForFieldTrials) { |
| 768 InstantiateFieldTrialAllocatorIfNeeded(); | 783 InstantiateFieldTrialAllocatorIfNeeded(); |
| 769 if (global_->readonly_allocator_handle_) | 784 if (global_->readonly_allocator_handle_) |
| 770 handles->push_back(global_->readonly_allocator_handle_); | 785 handles->push_back(global_->readonly_allocator_handle_); |
| 771 } | 786 } |
| 772 } | 787 } |
| 773 #endif | 788 #endif |
| 774 | 789 |
| 790 #if defined(OS_POSIX) && !defined(OS_NACL) | |
| 791 // static | |
| 792 int FieldTrialList::GetFieldTrialHandle() { | |
| 793 if (!global_) | |
| 794 return -1; | |
| 795 if (kUseSharedMemoryForFieldTrials) { | |
| 796 InstantiateFieldTrialAllocatorIfNeeded(); | |
| 797 if (global_->readonly_allocator_handle_ != -1) | |
| 798 return global_->readonly_allocator_handle_; | |
| 799 } | |
| 800 return -1; | |
| 801 } | |
| 802 #endif | |
| 803 | |
| 775 // static | 804 // static |
| 776 void FieldTrialList::CopyFieldTrialStateToFlags( | 805 void FieldTrialList::CopyFieldTrialStateToFlags( |
| 777 const char* field_trial_handle_switch, | 806 const char* field_trial_handle_switch, |
| 778 CommandLine* cmd_line) { | 807 CommandLine* cmd_line) { |
| 779 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, | 808 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, |
| 780 // content browser tests currently don't create a FieldTrialList because they | 809 // content browser tests currently don't create a FieldTrialList because they |
| 781 // don't run ChromeBrowserMainParts code where it's done for Chrome. | 810 // don't run ChromeBrowserMainParts code where it's done for Chrome. |
| 782 if (!global_) | 811 if (!global_) |
| 783 return; | 812 return; |
| 784 | 813 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 800 // retrieve the handle. See http://stackoverflow.com/a/153077 | 829 // retrieve the handle. See http://stackoverflow.com/a/153077 |
| 801 auto uintptr_handle = | 830 auto uintptr_handle = |
| 802 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); | 831 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); |
| 803 std::string field_trial_handle = std::to_string(uintptr_handle); | 832 std::string field_trial_handle = std::to_string(uintptr_handle); |
| 804 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); | 833 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); |
| 805 global_->field_trial_allocator_->UpdateTrackingHistograms(); | 834 global_->field_trial_allocator_->UpdateTrackingHistograms(); |
| 806 return; | 835 return; |
| 807 } | 836 } |
| 808 #endif | 837 #endif |
| 809 | 838 |
| 839 #if defined(POSIX_WITH_ZYGOTE) | |
| 840 // Use shared memory to pass the state if the feature is enabled, otherwise | |
| 841 // fallback to passing it via the command line as a string. | |
| 842 if (kUseSharedMemoryForFieldTrials) { | |
| 843 InstantiateFieldTrialAllocatorIfNeeded(); | |
| 844 // If the readonly handle didn't get duplicated properly, then fallback to | |
| 845 // original behavior. | |
| 846 if (global_->readonly_allocator_handle_ == -1) { | |
| 847 AddForceFieldTrialsFlag(cmd_line); | |
| 848 return; | |
| 849 } | |
| 850 | |
| 851 std::string field_trial_handle = | |
| 852 std::to_string(global_->readonly_allocator_handle_); | |
| 853 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); | |
| 854 global_->field_trial_allocator_->UpdateTrackingHistograms(); | |
| 855 return; | |
| 856 } | |
| 857 #endif | |
| 858 | |
| 810 AddForceFieldTrialsFlag(cmd_line); | 859 AddForceFieldTrialsFlag(cmd_line); |
| 811 } | 860 } |
| 812 | 861 |
| 813 // static | 862 // static |
| 814 FieldTrial* FieldTrialList::CreateFieldTrial( | 863 FieldTrial* FieldTrialList::CreateFieldTrial( |
| 815 const std::string& name, | 864 const std::string& name, |
| 816 const std::string& group_name) { | 865 const std::string& group_name) { |
| 817 DCHECK(global_); | 866 DCHECK(global_); |
| 818 DCHECK_GE(name.size(), 0u); | 867 DCHECK_GE(name.size(), 0u); |
| 819 DCHECK_GE(group_name.size(), 0u); | 868 DCHECK_GE(group_name.size(), 0u); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 886 } | 935 } |
| 887 | 936 |
| 888 // static | 937 // static |
| 889 size_t FieldTrialList::GetFieldTrialCount() { | 938 size_t FieldTrialList::GetFieldTrialCount() { |
| 890 if (!global_) | 939 if (!global_) |
| 891 return 0; | 940 return 0; |
| 892 AutoLock auto_lock(global_->lock_); | 941 AutoLock auto_lock(global_->lock_); |
| 893 return global_->registered_.size(); | 942 return global_->registered_.size(); |
| 894 } | 943 } |
| 895 | 944 |
| 945 // static | |
| 946 bool FieldTrialList::CreateTrialsFromHandleSwitch( | |
| 947 const std::string& handle_switch) { | |
| 896 #if defined(OS_WIN) | 948 #if defined(OS_WIN) |
| 949 int field_trial_handle = std::stoi(handle_switch); | |
| 950 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle); | |
| 951 SharedMemoryHandle shm_handle(handle, GetCurrentProcId()); | |
| 952 return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle); | |
| 953 #endif | |
| 954 | |
| 955 #if defined(POSIX_WITH_ZYGOTE) | |
| 956 int fd_key = std::stoi(handle_switch); | |
| 957 int fd = GlobalDescriptors::GetInstance()->Get(fd_key); | |
| 958 SharedMemoryHandle shm_handle(fd, true); | |
| 959 return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle); | |
| 960 #endif | |
| 961 | |
| 962 #if !defined(OS_WIN) && !defined(POSIX_WITH_ZYGOTE) | |
| 963 return false; | |
| 964 #endif | |
| 965 } | |
| 966 | |
| 967 #if !defined(OS_NACL) | |
| 897 // static | 968 // static |
| 898 bool FieldTrialList::CreateTrialsFromWindowsHandle(HANDLE handle) { | 969 bool FieldTrialList::CreateTrialsFromSharedMemoryHandle( |
| 899 SharedMemoryHandle shm_handle(handle, GetCurrentProcId()); | 970 SharedMemoryHandle shm_handle) { |
| 900 | |
| 901 // shm gets deleted when it gets out of scope, but that's OK because we need | 971 // shm gets deleted when it gets out of scope, but that's OK because we need |
| 902 // it only for the duration of this method. | 972 // it only for the duration of this method. |
| 903 std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true)); | 973 std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true)); |
| 904 if (!shm.get()->Map(kFieldTrialAllocationSize)) | 974 if (!shm.get()->Map(kFieldTrialAllocationSize)) |
| 905 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); | 975 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); |
| 906 | 976 |
| 907 return FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm)); | 977 return FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm)); |
| 908 } | 978 } |
| 909 #endif | 979 #endif |
| 910 | 980 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 980 #if !defined(OS_NACL) | 1050 #if !defined(OS_NACL) |
| 981 // static | 1051 // static |
| 982 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() { | 1052 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() { |
| 983 if (!global_) | 1053 if (!global_) |
| 984 return; | 1054 return; |
| 985 AutoLock auto_lock(global_->lock_); | 1055 AutoLock auto_lock(global_->lock_); |
| 986 // Create the allocator if not already created and add all existing trials. | 1056 // Create the allocator if not already created and add all existing trials. |
| 987 if (global_->field_trial_allocator_ != nullptr) | 1057 if (global_->field_trial_allocator_ != nullptr) |
| 988 return; | 1058 return; |
| 989 | 1059 |
| 1060 SharedMemoryCreateOptions options; | |
| 1061 options.size = kFieldTrialAllocationSize; | |
| 1062 options.share_read_only = true; | |
| 1063 | |
| 990 std::unique_ptr<SharedMemory> shm(new SharedMemory()); | 1064 std::unique_ptr<SharedMemory> shm(new SharedMemory()); |
| 991 if (!shm->CreateAndMapAnonymous(kFieldTrialAllocationSize)) | 1065 if (!shm->Create(options)) |
| 1066 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); | |
| 1067 | |
| 1068 if (!shm->Map(kFieldTrialAllocationSize)) | |
| 992 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); | 1069 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); |
| 993 | 1070 |
| 994 global_->field_trial_allocator_.reset( | 1071 global_->field_trial_allocator_.reset( |
| 995 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); | 1072 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); |
| 996 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); | 1073 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); |
| 997 | 1074 |
| 998 // Add all existing field trials. | 1075 // Add all existing field trials. |
| 999 for (const auto& registered : global_->registered_) { | 1076 for (const auto& registered : global_->registered_) { |
| 1000 AddToAllocatorWhileLocked(registered.second); | 1077 AddToAllocatorWhileLocked(registered.second); |
| 1001 } | 1078 } |
| 1002 | 1079 |
| 1003 #if defined(OS_WIN) | 1080 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) |
| 1004 // Set |readonly_allocator_handle_| so we can pass it to be inherited and | 1081 // Set |readonly_allocator_handle_| so we can pass it to be inherited and |
| 1005 // via the command line. | 1082 // via the command line. |
| 1006 global_->readonly_allocator_handle_ = | 1083 global_->readonly_allocator_handle_ = |
| 1007 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); | 1084 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); |
| 1008 #endif | 1085 #endif |
| 1009 } | 1086 } |
| 1010 #endif | 1087 #endif |
| 1011 | 1088 |
| 1012 // static | 1089 // static |
| 1013 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { | 1090 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1108 return; | 1185 return; |
| 1109 } | 1186 } |
| 1110 AutoLock auto_lock(global_->lock_); | 1187 AutoLock auto_lock(global_->lock_); |
| 1111 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1188 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
| 1112 trial->AddRef(); | 1189 trial->AddRef(); |
| 1113 trial->SetTrialRegistered(); | 1190 trial->SetTrialRegistered(); |
| 1114 global_->registered_[trial->trial_name()] = trial; | 1191 global_->registered_[trial->trial_name()] = trial; |
| 1115 } | 1192 } |
| 1116 | 1193 |
| 1117 } // namespace base | 1194 } // namespace base |
| OLD | NEW |