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