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 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
226 } | 237 } |
227 } | 238 } |
228 | 239 |
229 #if defined(OS_WIN) | 240 #if defined(OS_WIN) |
230 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { | 241 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { |
231 HANDLE src = allocator->shared_memory()->handle().GetHandle(); | 242 HANDLE src = allocator->shared_memory()->handle().GetHandle(); |
232 ProcessHandle process = GetCurrentProcess(); | 243 ProcessHandle process = GetCurrentProcess(); |
233 DWORD access = SECTION_MAP_READ | SECTION_QUERY; | 244 DWORD access = SECTION_MAP_READ | SECTION_QUERY; |
234 HANDLE dst; | 245 HANDLE dst; |
235 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) | 246 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) |
236 return nullptr; | 247 return kInvalidPlatformHandle; |
237 return dst; | 248 return dst; |
238 } | 249 } |
239 #endif | 250 #endif |
240 | 251 |
252 #if defined(POSIX_WITH_ZYGOTE) | |
253 int CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { | |
254 SharedMemoryHandle new_handle; | |
255 allocator->shared_memory()->ShareReadOnlyToProcess(GetCurrentProcessHandle(), | |
256 &new_handle); | |
257 return SharedMemory::GetFdFromSharedMemoryHandle(new_handle); | |
258 } | |
259 #endif | |
260 | |
241 } // namespace | 261 } // namespace |
242 | 262 |
243 // statics | 263 // statics |
244 const int FieldTrial::kNotFinalized = -1; | 264 const int FieldTrial::kNotFinalized = -1; |
245 const int FieldTrial::kDefaultGroupNumber = 0; | 265 const int FieldTrial::kDefaultGroupNumber = 0; |
246 bool FieldTrial::enable_benchmarking_ = false; | 266 bool FieldTrial::enable_benchmarking_ = false; |
247 | 267 |
248 int FieldTrialList::kNoExpirationYear = 0; | 268 int FieldTrialList::kNoExpirationYear = 0; |
249 | 269 |
250 //------------------------------------------------------------------------------ | 270 //------------------------------------------------------------------------------ |
(...skipping 482 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
733 } | 753 } |
734 return true; | 754 return true; |
735 } | 755 } |
736 | 756 |
737 // static | 757 // static |
738 void FieldTrialList::CreateTrialsFromCommandLine( | 758 void FieldTrialList::CreateTrialsFromCommandLine( |
739 const CommandLine& cmd_line, | 759 const CommandLine& cmd_line, |
740 const char* field_trial_handle_switch) { | 760 const char* field_trial_handle_switch) { |
741 global_->create_trials_from_command_line_called_ = true; | 761 global_->create_trials_from_command_line_called_ = true; |
742 | 762 |
743 #if defined(OS_WIN) && !defined(OS_NACL) | |
744 if (cmd_line.HasSwitch(field_trial_handle_switch)) { | 763 if (cmd_line.HasSwitch(field_trial_handle_switch)) { |
745 std::string arg = cmd_line.GetSwitchValueASCII(field_trial_handle_switch); | 764 std::string handle_switch = |
746 int field_trial_handle = std::stoi(arg); | 765 cmd_line.GetSwitchValueASCII(field_trial_handle_switch); |
747 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle); | 766 bool result = CreateTrialsFromHandleSwitch(handle_switch); |
748 bool result = CreateTrialsFromWindowsHandle(handle); | |
749 DCHECK(result); | 767 DCHECK(result); |
750 } | 768 } |
751 #endif | |
752 | 769 |
753 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { | 770 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { |
754 bool result = FieldTrialList::CreateTrialsFromString( | 771 bool result = FieldTrialList::CreateTrialsFromString( |
755 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), | 772 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), |
756 std::set<std::string>()); | 773 std::set<std::string>()); |
757 DCHECK(result); | 774 DCHECK(result); |
758 } | 775 } |
759 } | 776 } |
760 | 777 |
761 #if defined(OS_WIN) | 778 #if defined(OS_WIN) |
762 // static | 779 // static |
763 void FieldTrialList::AppendFieldTrialHandleIfNeeded( | 780 void FieldTrialList::AppendFieldTrialHandleIfNeeded( |
764 HandlesToInheritVector* handles) { | 781 HandlesToInheritVector* handles) { |
765 if (!global_) | 782 if (!global_) |
766 return; | 783 return; |
767 if (kUseSharedMemoryForFieldTrials) { | 784 if (kUseSharedMemoryForFieldTrials) { |
768 InstantiateFieldTrialAllocatorIfNeeded(); | 785 InstantiateFieldTrialAllocatorIfNeeded(); |
769 if (global_->readonly_allocator_handle_) | 786 if (global_->readonly_allocator_handle_) |
770 handles->push_back(global_->readonly_allocator_handle_); | 787 handles->push_back(global_->readonly_allocator_handle_); |
771 } | 788 } |
772 } | 789 } |
773 #endif | 790 #endif |
774 | 791 |
792 #if defined(OS_POSIX) && !defined(OS_NACL) | |
793 // static | |
794 int FieldTrialList::GetFieldTrialHandle() { | |
795 if (!global_) | |
796 return kInvalidPlatformFile; | |
797 if (kUseSharedMemoryForFieldTrials) { | |
798 InstantiateFieldTrialAllocatorIfNeeded(); | |
799 if (global_->readonly_allocator_handle_ != kInvalidPlatformFile) | |
Alexei Svitkine (slow)
2016/11/24 19:04:39
Nit: Seems this if is not needed - since if it's k
lawrencewu
2016/11/24 19:14:57
Done.
| |
800 return global_->readonly_allocator_handle_; | |
801 } | |
802 return kInvalidPlatformFile; | |
803 } | |
804 #endif | |
805 | |
775 // static | 806 // static |
776 void FieldTrialList::CopyFieldTrialStateToFlags( | 807 void FieldTrialList::CopyFieldTrialStateToFlags( |
777 const char* field_trial_handle_switch, | 808 const char* field_trial_handle_switch, |
778 CommandLine* cmd_line) { | 809 CommandLine* cmd_line) { |
779 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, | 810 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, |
780 // content browser tests currently don't create a FieldTrialList because they | 811 // content browser tests currently don't create a FieldTrialList because they |
781 // don't run ChromeBrowserMainParts code where it's done for Chrome. | 812 // don't run ChromeBrowserMainParts code where it's done for Chrome. |
782 if (!global_) | 813 if (!global_) |
783 return; | 814 return; |
784 | 815 |
785 #if defined(OS_WIN) | 816 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) |
786 // Use shared memory to pass the state if the feature is enabled, otherwise | 817 // Use shared memory to pass the state if the feature is enabled, otherwise |
787 // fallback to passing it via the command line as a string. | 818 // fallback to passing it via the command line as a string. |
788 if (kUseSharedMemoryForFieldTrials) { | 819 if (kUseSharedMemoryForFieldTrials) { |
789 InstantiateFieldTrialAllocatorIfNeeded(); | 820 InstantiateFieldTrialAllocatorIfNeeded(); |
790 // If the readonly handle didn't get duplicated properly, then fallback to | 821 // If the readonly handle didn't get duplicated properly, then fallback to |
791 // original behavior. | 822 // original behavior. |
792 if (!global_->readonly_allocator_handle_) { | 823 if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) { |
793 AddForceFieldTrialsFlag(cmd_line); | 824 AddForceFieldTrialsFlag(cmd_line); |
794 return; | 825 return; |
795 } | 826 } |
796 | 827 |
797 // HANDLE is just typedef'd to void *. We basically cast the handle into an | 828 #if defined(OS_WIN) |
798 // int (uintptr_t, to be exact), stringify the int, and pass it as a | 829 // PlatformFile is typedef'd to HANDLE which is typedef'd to void *. We |
799 // command-line flag. The child process will do the reverse conversions to | 830 // basically cast the handle into an int (uintptr_t, to be exact), stringify |
800 // retrieve the handle. See http://stackoverflow.com/a/153077 | 831 // the int, and pass it as a command-line flag. The child process will do |
832 // the reverse conversions to retrieve the handle. See | |
833 // http://stackoverflow.com/a/153077 | |
801 auto uintptr_handle = | 834 auto uintptr_handle = |
802 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); | 835 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); |
803 std::string field_trial_handle = std::to_string(uintptr_handle); | 836 std::string field_trial_handle = std::to_string(uintptr_handle); |
837 #elif defined(POSIX_WITH_ZYGOTE) | |
838 // On POSIX we can straight-up cast the handle into a string, since it's | |
839 // just an int. | |
840 std::string field_trial_handle = | |
841 std::to_string(global_->readonly_allocator_handle_); | |
842 #endif | |
804 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); | 843 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); |
805 global_->field_trial_allocator_->UpdateTrackingHistograms(); | 844 global_->field_trial_allocator_->UpdateTrackingHistograms(); |
806 return; | 845 return; |
807 } | 846 } |
808 #endif | 847 #endif |
809 | 848 |
810 AddForceFieldTrialsFlag(cmd_line); | 849 AddForceFieldTrialsFlag(cmd_line); |
811 } | 850 } |
812 | 851 |
813 // static | 852 // static |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
886 } | 925 } |
887 | 926 |
888 // static | 927 // static |
889 size_t FieldTrialList::GetFieldTrialCount() { | 928 size_t FieldTrialList::GetFieldTrialCount() { |
890 if (!global_) | 929 if (!global_) |
891 return 0; | 930 return 0; |
892 AutoLock auto_lock(global_->lock_); | 931 AutoLock auto_lock(global_->lock_); |
893 return global_->registered_.size(); | 932 return global_->registered_.size(); |
894 } | 933 } |
895 | 934 |
935 // static | |
936 bool FieldTrialList::CreateTrialsFromHandleSwitch( | |
937 const std::string& handle_switch) { | |
896 #if defined(OS_WIN) | 938 #if defined(OS_WIN) |
939 int field_trial_handle = std::stoi(handle_switch); | |
940 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle); | |
941 SharedMemoryHandle shm_handle(handle, GetCurrentProcId()); | |
942 return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle); | |
943 #endif | |
944 | |
945 #if defined(POSIX_WITH_ZYGOTE) | |
946 int fd_key = std::stoi(handle_switch); | |
947 int fd = GlobalDescriptors::GetInstance()->Get(fd_key); | |
948 SharedMemoryHandle shm_handle(fd, true); | |
949 return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle); | |
950 #endif | |
951 | |
952 #if !defined(OS_WIN) && !defined(POSIX_WITH_ZYGOTE) | |
953 return false; | |
954 #endif | |
955 } | |
956 | |
957 #if !defined(OS_NACL) | |
897 // static | 958 // static |
898 bool FieldTrialList::CreateTrialsFromWindowsHandle(HANDLE handle) { | 959 bool FieldTrialList::CreateTrialsFromSharedMemoryHandle( |
899 SharedMemoryHandle shm_handle(handle, GetCurrentProcId()); | 960 SharedMemoryHandle shm_handle) { |
900 | |
901 // shm gets deleted when it gets out of scope, but that's OK because we need | 961 // 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. | 962 // it only for the duration of this method. |
903 std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true)); | 963 std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true)); |
904 if (!shm.get()->Map(kFieldTrialAllocationSize)) | 964 if (!shm.get()->Map(kFieldTrialAllocationSize)) |
905 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); | 965 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); |
906 | 966 |
907 return FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm)); | 967 return FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm)); |
908 } | 968 } |
909 #endif | 969 #endif |
910 | 970 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
980 #if !defined(OS_NACL) | 1040 #if !defined(OS_NACL) |
981 // static | 1041 // static |
982 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() { | 1042 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() { |
983 if (!global_) | 1043 if (!global_) |
984 return; | 1044 return; |
985 AutoLock auto_lock(global_->lock_); | 1045 AutoLock auto_lock(global_->lock_); |
986 // Create the allocator if not already created and add all existing trials. | 1046 // Create the allocator if not already created and add all existing trials. |
987 if (global_->field_trial_allocator_ != nullptr) | 1047 if (global_->field_trial_allocator_ != nullptr) |
988 return; | 1048 return; |
989 | 1049 |
1050 SharedMemoryCreateOptions options; | |
1051 options.size = kFieldTrialAllocationSize; | |
1052 options.share_read_only = true; | |
1053 | |
990 std::unique_ptr<SharedMemory> shm(new SharedMemory()); | 1054 std::unique_ptr<SharedMemory> shm(new SharedMemory()); |
991 if (!shm->CreateAndMapAnonymous(kFieldTrialAllocationSize)) | 1055 if (!shm->Create(options)) |
1056 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); | |
1057 | |
1058 if (!shm->Map(kFieldTrialAllocationSize)) | |
992 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); | 1059 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); |
993 | 1060 |
994 global_->field_trial_allocator_.reset( | 1061 global_->field_trial_allocator_.reset( |
995 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); | 1062 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); |
996 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); | 1063 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); |
997 | 1064 |
998 // Add all existing field trials. | 1065 // Add all existing field trials. |
999 for (const auto& registered : global_->registered_) { | 1066 for (const auto& registered : global_->registered_) { |
1000 AddToAllocatorWhileLocked(registered.second); | 1067 AddToAllocatorWhileLocked(registered.second); |
1001 } | 1068 } |
1002 | 1069 |
1003 #if defined(OS_WIN) | 1070 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) |
1004 // Set |readonly_allocator_handle_| so we can pass it to be inherited and | 1071 // Set |readonly_allocator_handle_| so we can pass it to be inherited and |
1005 // via the command line. | 1072 // via the command line. |
1006 global_->readonly_allocator_handle_ = | 1073 global_->readonly_allocator_handle_ = |
1007 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); | 1074 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); |
1008 #endif | 1075 #endif |
1009 } | 1076 } |
1010 #endif | 1077 #endif |
1011 | 1078 |
1012 // static | 1079 // static |
1013 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { | 1080 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1108 return; | 1175 return; |
1109 } | 1176 } |
1110 AutoLock auto_lock(global_->lock_); | 1177 AutoLock auto_lock(global_->lock_); |
1111 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1178 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
1112 trial->AddRef(); | 1179 trial->AddRef(); |
1113 trial->SetTrialRegistered(); | 1180 trial->SetTrialRegistered(); |
1114 global_->registered_[trial->trial_name()] = trial; | 1181 global_->registered_[trial->trial_name()] = trial; |
1115 } | 1182 } |
1116 | 1183 |
1117 } // namespace base | 1184 } // namespace base |
OLD | NEW |