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/logging.h" | 13 #include "base/logging.h" |
14 #include "base/metrics/field_trial_param_associator.h" | 14 #include "base/metrics/field_trial_param_associator.h" |
15 #include "base/pickle.h" | 15 #include "base/pickle.h" |
16 #include "base/process/memory.h" | 16 #include "base/process/memory.h" |
17 #include "base/rand_util.h" | 17 #include "base/rand_util.h" |
18 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
19 #include "base/strings/string_util.h" | 19 #include "base/strings/string_util.h" |
20 #include "base/strings/stringprintf.h" | 20 #include "base/strings/stringprintf.h" |
21 #include "base/strings/utf_string_conversions.h" | 21 #include "base/strings/utf_string_conversions.h" |
22 | 22 |
23 // On systems that use the zygote process to spawn child processes, we must | 23 // On systems that use the zygote process to spawn child processes, we must |
24 // retrieve the correct fd using the mapping in GlobalDescriptors. | 24 // retrieve the correct fd using the mapping in GlobalDescriptors. |
25 #if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_MACOSX) && \ | 25 #if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_MACOSX) && \ |
26 !defined(OS_ANDROID) | 26 !defined(OS_ANDROID) |
27 #define POSIX_WITH_ZYGOTE 1 | 27 #define POSIX_WITH_ZYGOTE 1 |
28 #endif | 28 #endif |
29 | 29 |
30 #if defined(POSIX_WITH_ZYGOTE) | 30 #if defined(POSIX_WITH_ZYGOTE) || defined(OS_MACOSX) |
31 #include "base/posix/global_descriptors.h" | 31 #include "base/posix/global_descriptors.h" |
32 #endif | 32 #endif |
33 | 33 |
34 namespace base { | 34 namespace base { |
35 | 35 |
36 namespace { | 36 namespace { |
37 | 37 |
38 // Define a separator character to use when creating a persistent form of an | 38 // Define a separator character to use when creating a persistent form of an |
39 // instance. This is intended for use as a command line argument, passed to a | 39 // instance. This is intended for use as a command line argument, passed to a |
40 // second process to mimic our state (i.e., provide the same group name). | 40 // second process to mimic our state (i.e., provide the same group name). |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
277 HANDLE src = allocator->shared_memory()->handle().GetHandle(); | 277 HANDLE src = allocator->shared_memory()->handle().GetHandle(); |
278 ProcessHandle process = GetCurrentProcess(); | 278 ProcessHandle process = GetCurrentProcess(); |
279 DWORD access = SECTION_MAP_READ | SECTION_QUERY; | 279 DWORD access = SECTION_MAP_READ | SECTION_QUERY; |
280 HANDLE dst; | 280 HANDLE dst; |
281 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) | 281 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) |
282 return kInvalidPlatformFile; | 282 return kInvalidPlatformFile; |
283 return dst; | 283 return dst; |
284 } | 284 } |
285 #endif | 285 #endif |
286 | 286 |
287 #if defined(POSIX_WITH_ZYGOTE) | 287 #if defined(POSIX_WITH_ZYGOTE) || defined(OS_MACOSX) |
288 int CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { | 288 int CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { |
289 SharedMemoryHandle new_handle; | 289 SharedMemoryHandle new_handle; |
290 allocator->shared_memory()->ShareReadOnlyToProcess(GetCurrentProcessHandle(), | 290 allocator->shared_memory()->ShareReadOnlyToProcess(GetCurrentProcessHandle(), |
291 &new_handle); | 291 &new_handle); |
292 return SharedMemory::GetFdFromSharedMemoryHandle(new_handle); | 292 return SharedMemory::GetFdFromSharedMemoryHandle(new_handle); |
293 } | 293 } |
294 #endif | 294 #endif |
295 | 295 |
296 } // namespace | 296 } // namespace |
297 | 297 |
(...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
798 | 798 |
799 #if defined(OS_WIN) | 799 #if defined(OS_WIN) |
800 if (cmd_line.HasSwitch(field_trial_handle_switch)) { | 800 if (cmd_line.HasSwitch(field_trial_handle_switch)) { |
801 std::string handle_switch = | 801 std::string handle_switch = |
802 cmd_line.GetSwitchValueASCII(field_trial_handle_switch); | 802 cmd_line.GetSwitchValueASCII(field_trial_handle_switch); |
803 bool result = CreateTrialsFromHandleSwitch(handle_switch); | 803 bool result = CreateTrialsFromHandleSwitch(handle_switch); |
804 DCHECK(result); | 804 DCHECK(result); |
805 } | 805 } |
806 #endif | 806 #endif |
807 | 807 |
808 #if defined(POSIX_WITH_ZYGOTE) | 808 #if defined(POSIX_WITH_ZYGOTE) || defined(OS_MACOSX) |
809 // If we failed to create trials from the descriptor, fallback to the command | 809 // On POSIX, we check if the handle is valid by seeing if the browser process |
810 // line. Otherwise we're good -- return. | 810 // sent over the switch (we don't care about the value). Invalid handles |
811 if (CreateTrialsFromDescriptor(fd_key)) | 811 // occur in some browser tests which don't initialize the allocator. |
812 return; | 812 if (cmd_line.HasSwitch(field_trial_handle_switch)) { |
813 bool result = CreateTrialsFromDescriptor(fd_key); | |
814 DCHECK(result); | |
815 } | |
813 #endif | 816 #endif |
814 | 817 |
815 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { | 818 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { |
816 bool result = FieldTrialList::CreateTrialsFromString( | 819 bool result = FieldTrialList::CreateTrialsFromString( |
817 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), | 820 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), |
818 std::set<std::string>()); | 821 std::set<std::string>()); |
819 DCHECK(result); | 822 DCHECK(result); |
820 } | 823 } |
821 } | 824 } |
822 | 825 |
823 // static | 826 // static |
824 void FieldTrialList::CreateFeaturesFromCommandLine( | 827 void FieldTrialList::CreateFeaturesFromCommandLine( |
825 const base::CommandLine& command_line, | 828 const base::CommandLine& command_line, |
826 const char* enable_features_switch, | 829 const char* enable_features_switch, |
827 const char* disable_features_switch, | 830 const char* disable_features_switch, |
828 FeatureList* feature_list) { | 831 FeatureList* feature_list) { |
829 // Fallback to command line if not using shared memory. | 832 // Fallback to command line if not using shared memory. |
830 if (!kUseSharedMemoryForFieldTrials || | 833 if (!kUseSharedMemoryForFieldTrials || |
831 !global_->field_trial_allocator_.get()) { | 834 !global_->field_trial_allocator_.get()) { |
832 return feature_list->InitializeFromCommandLine( | 835 return feature_list->InitializeFromCommandLine( |
833 command_line.GetSwitchValueASCII(enable_features_switch), | 836 command_line.GetSwitchValueASCII(enable_features_switch), |
834 command_line.GetSwitchValueASCII(disable_features_switch)); | 837 command_line.GetSwitchValueASCII(disable_features_switch)); |
835 } | 838 } |
836 | 839 |
837 feature_list->InitializeFromSharedMemory( | 840 feature_list->InitializeFromSharedMemory( |
838 global_->field_trial_allocator_.get()); | 841 global_->field_trial_allocator_.get()); |
839 } | 842 } |
840 | 843 |
841 #if defined(POSIX_WITH_ZYGOTE) | 844 #if defined(POSIX_WITH_ZYGOTE) || defined(OS_MACOSX) |
842 // static | 845 // static |
843 bool FieldTrialList::CreateTrialsFromDescriptor(int fd_key) { | 846 bool FieldTrialList::CreateTrialsFromDescriptor(int fd_key) { |
844 if (!kUseSharedMemoryForFieldTrials) | 847 if (!kUseSharedMemoryForFieldTrials) |
845 return false; | 848 return false; |
846 | 849 |
847 if (fd_key == -1) | 850 if (fd_key == -1) |
848 return false; | 851 return false; |
849 | 852 |
850 int fd = GlobalDescriptors::GetInstance()->MaybeGet(fd_key); | 853 int fd = GlobalDescriptors::GetInstance()->MaybeGet(fd_key); |
851 if (fd == -1) | 854 if (fd == -1) |
852 return false; | 855 return false; |
853 | 856 |
857 #if defined(POSIX_WITH_ZYGOTE) | |
854 SharedMemoryHandle shm_handle(fd, true); | 858 SharedMemoryHandle shm_handle(fd, true); |
859 #elif defined(OS_MACOSX) | |
860 SharedMemoryHandle shm_handle(FileDescriptor(fd, true)); | |
861 #endif | |
862 | |
855 bool result = FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle); | 863 bool result = FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle); |
856 DCHECK(result); | 864 DCHECK(result); |
857 return true; | 865 return true; |
858 } | 866 } |
859 #endif | 867 #endif |
860 | 868 |
861 #if defined(OS_WIN) | 869 #if defined(OS_WIN) |
862 // static | 870 // static |
863 void FieldTrialList::AppendFieldTrialHandleIfNeeded( | 871 void FieldTrialList::AppendFieldTrialHandleIfNeeded( |
864 HandlesToInheritVector* handles) { | 872 HandlesToInheritVector* handles) { |
(...skipping 29 matching lines...) Expand all Loading... | |
894 // content browser tests currently don't create a FieldTrialList because they | 902 // content browser tests currently don't create a FieldTrialList because they |
895 // don't run ChromeBrowserMainParts code where it's done for Chrome. | 903 // don't run ChromeBrowserMainParts code where it's done for Chrome. |
896 // Some tests depend on the enable and disable features flag switch, though, | 904 // Some tests depend on the enable and disable features flag switch, though, |
897 // so we can still add those even though AllStatesToString() will be a no-op. | 905 // so we can still add those even though AllStatesToString() will be a no-op. |
898 if (!global_) { | 906 if (!global_) { |
899 AddFeatureAndFieldTrialFlags(enable_features_switch, | 907 AddFeatureAndFieldTrialFlags(enable_features_switch, |
900 disable_features_switch, cmd_line); | 908 disable_features_switch, cmd_line); |
901 return; | 909 return; |
902 } | 910 } |
903 | 911 |
904 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) | 912 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) || defined(OS_MACOSX) |
905 // Use shared memory to pass the state if the feature is enabled, otherwise | 913 // Use shared memory to pass the state if the feature is enabled, otherwise |
906 // fallback to passing it via the command line as a string. | 914 // fallback to passing it via the command line as a string. |
907 if (kUseSharedMemoryForFieldTrials) { | 915 if (kUseSharedMemoryForFieldTrials) { |
908 InstantiateFieldTrialAllocatorIfNeeded(); | 916 InstantiateFieldTrialAllocatorIfNeeded(); |
909 // If the readonly handle didn't get duplicated properly, then fallback to | 917 // If the readonly handle didn't get duplicated properly, then fallback to |
910 // original behavior. | 918 // original behavior. |
911 if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) { | 919 if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) { |
912 AddFeatureAndFieldTrialFlags(enable_features_switch, | 920 AddFeatureAndFieldTrialFlags(enable_features_switch, |
913 disable_features_switch, cmd_line); | 921 disable_features_switch, cmd_line); |
914 return; | 922 return; |
915 } | 923 } |
916 | 924 |
917 global_->field_trial_allocator_->UpdateTrackingHistograms(); | 925 global_->field_trial_allocator_->UpdateTrackingHistograms(); |
918 | 926 |
919 #if defined(OS_WIN) | 927 #if defined(OS_WIN) |
920 // We need to pass a named anonymous handle to shared memory over the | 928 // We need to pass a named anonymous handle to shared memory over the |
921 // command line on Windows, since the child doesn't know which of the | 929 // command line on Windows, since the child doesn't know which of the |
922 // handles it inherited it should open. On POSIX, we don't need to do this | 930 // handles it inherited it should open. |
923 // -- we dup the fd into a fixed fd kFieldTrialDescriptor, so we can just | |
924 // look it up there. | |
925 // PlatformFile is typedef'd to HANDLE which is typedef'd to void *. We | 931 // PlatformFile is typedef'd to HANDLE which is typedef'd to void *. We |
926 // basically cast the handle into an int (uintptr_t, to be exact), stringify | 932 // basically cast the handle into an int (uintptr_t, to be exact), stringify |
927 // the int, and pass it as a command-line flag. The child process will do | 933 // the int, and pass it as a command-line flag. The child process will do |
928 // the reverse conversions to retrieve the handle. See | 934 // the reverse conversions to retrieve the handle. See |
929 // http://stackoverflow.com/a/153077 | 935 // http://stackoverflow.com/a/153077 |
930 auto uintptr_handle = | 936 auto uintptr_handle = |
931 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); | 937 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); |
932 std::string field_trial_handle = std::to_string(uintptr_handle); | 938 std::string field_trial_handle = std::to_string(uintptr_handle); |
933 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); | 939 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); |
940 #elif defined(POSIX_WITH_ZYGOTE) || defined(OS_MACOSX) | |
941 // On POSIX, we dup the fd into a fixed fd kFieldTrialDescriptor, so we | |
942 // don't have to pass over the handle (it's not even the right handle | |
943 // anyways). But some browser tests don't create the allocator, so we need | |
944 // to be able to distinguish valid and invalid handles. | |
945 std::string field_trial_handle = | |
946 std::to_string(global_->readonly_allocator_handle_); | |
947 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); | |
Alexei Svitkine (slow)
2016/12/12 16:02:39
If in this case you're using the param with an int
lawrencewu
2016/12/13 17:18:40
Done.
| |
934 #endif | 948 #endif |
935 return; | 949 return; |
936 } | 950 } |
937 #endif | 951 #endif |
938 | 952 |
939 AddFeatureAndFieldTrialFlags(enable_features_switch, disable_features_switch, | 953 AddFeatureAndFieldTrialFlags(enable_features_switch, disable_features_switch, |
940 cmd_line); | 954 cmd_line); |
941 } | 955 } |
942 | 956 |
943 // static | 957 // static |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1189 if (!global_) | 1203 if (!global_) |
1190 return; | 1204 return; |
1191 AutoLock auto_lock(global_->lock_); | 1205 AutoLock auto_lock(global_->lock_); |
1192 // Create the allocator if not already created and add all existing trials. | 1206 // Create the allocator if not already created and add all existing trials. |
1193 if (global_->field_trial_allocator_ != nullptr) | 1207 if (global_->field_trial_allocator_ != nullptr) |
1194 return; | 1208 return; |
1195 | 1209 |
1196 SharedMemoryCreateOptions options; | 1210 SharedMemoryCreateOptions options; |
1197 options.size = kFieldTrialAllocationSize; | 1211 options.size = kFieldTrialAllocationSize; |
1198 options.share_read_only = true; | 1212 options.share_read_only = true; |
1213 #if defined(OS_MACOSX) && !defined(OS_IOS) | |
1214 options.type = SharedMemoryHandle::POSIX; | |
1215 #endif | |
1199 | 1216 |
1200 std::unique_ptr<SharedMemory> shm(new SharedMemory()); | 1217 std::unique_ptr<SharedMemory> shm(new SharedMemory()); |
1201 if (!shm->Create(options)) | 1218 if (!shm->Create(options)) |
1202 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); | 1219 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); |
1203 | 1220 |
1204 if (!shm->Map(kFieldTrialAllocationSize)) | 1221 if (!shm->Map(kFieldTrialAllocationSize)) |
1205 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); | 1222 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); |
1206 | 1223 |
1207 global_->field_trial_allocator_.reset( | 1224 global_->field_trial_allocator_.reset( |
1208 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); | 1225 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); |
1209 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); | 1226 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); |
1210 | 1227 |
1211 // Add all existing field trials. | 1228 // Add all existing field trials. |
1212 for (const auto& registered : global_->registered_) { | 1229 for (const auto& registered : global_->registered_) { |
1213 AddToAllocatorWhileLocked(registered.second); | 1230 AddToAllocatorWhileLocked(registered.second); |
1214 } | 1231 } |
1215 | 1232 |
1216 // Add all existing features. | 1233 // Add all existing features. |
1217 FeatureList::GetInstance()->AddFeaturesToAllocator( | 1234 FeatureList::GetInstance()->AddFeaturesToAllocator( |
1218 global_->field_trial_allocator_.get()); | 1235 global_->field_trial_allocator_.get()); |
1219 | 1236 |
1220 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) | 1237 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) || defined(OS_MACOSX) |
1221 // Set |readonly_allocator_handle_| so we can pass it to be inherited and | 1238 // Set |readonly_allocator_handle_| so we can pass it to be inherited and |
1222 // via the command line. | 1239 // via the command line. |
1223 global_->readonly_allocator_handle_ = | 1240 global_->readonly_allocator_handle_ = |
1224 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); | 1241 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); |
1225 #endif | 1242 #endif |
1226 } | 1243 } |
1227 #endif | 1244 #endif |
1228 | 1245 |
1229 // static | 1246 // static |
1230 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { | 1247 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1325 return; | 1342 return; |
1326 } | 1343 } |
1327 AutoLock auto_lock(global_->lock_); | 1344 AutoLock auto_lock(global_->lock_); |
1328 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1345 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
1329 trial->AddRef(); | 1346 trial->AddRef(); |
1330 trial->SetTrialRegistered(); | 1347 trial->SetTrialRegistered(); |
1331 global_->registered_[trial->trial_name()] = trial; | 1348 global_->registered_[trial->trial_name()] = trial; |
1332 } | 1349 } |
1333 | 1350 |
1334 } // namespace base | 1351 } // namespace base |
OLD | NEW |