| 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. We do that by just |
| 945 // checking that the flag is set with a dummy value. |
| 946 cmd_line->AppendSwitchASCII(field_trial_handle_switch, "1"); |
| 934 #endif | 947 #endif |
| 935 return; | 948 return; |
| 936 } | 949 } |
| 937 #endif | 950 #endif |
| 938 | 951 |
| 939 AddFeatureAndFieldTrialFlags(enable_features_switch, disable_features_switch, | 952 AddFeatureAndFieldTrialFlags(enable_features_switch, disable_features_switch, |
| 940 cmd_line); | 953 cmd_line); |
| 941 } | 954 } |
| 942 | 955 |
| 943 // static | 956 // static |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1189 if (!global_) | 1202 if (!global_) |
| 1190 return; | 1203 return; |
| 1191 AutoLock auto_lock(global_->lock_); | 1204 AutoLock auto_lock(global_->lock_); |
| 1192 // Create the allocator if not already created and add all existing trials. | 1205 // Create the allocator if not already created and add all existing trials. |
| 1193 if (global_->field_trial_allocator_ != nullptr) | 1206 if (global_->field_trial_allocator_ != nullptr) |
| 1194 return; | 1207 return; |
| 1195 | 1208 |
| 1196 SharedMemoryCreateOptions options; | 1209 SharedMemoryCreateOptions options; |
| 1197 options.size = kFieldTrialAllocationSize; | 1210 options.size = kFieldTrialAllocationSize; |
| 1198 options.share_read_only = true; | 1211 options.share_read_only = true; |
| 1212 #if defined(OS_MACOSX) && !defined(OS_IOS) |
| 1213 options.type = SharedMemoryHandle::POSIX; |
| 1214 #endif |
| 1199 | 1215 |
| 1200 std::unique_ptr<SharedMemory> shm(new SharedMemory()); | 1216 std::unique_ptr<SharedMemory> shm(new SharedMemory()); |
| 1201 if (!shm->Create(options)) | 1217 if (!shm->Create(options)) |
| 1202 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); | 1218 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); |
| 1203 | 1219 |
| 1204 if (!shm->Map(kFieldTrialAllocationSize)) | 1220 if (!shm->Map(kFieldTrialAllocationSize)) |
| 1205 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); | 1221 TerminateBecauseOutOfMemory(kFieldTrialAllocationSize); |
| 1206 | 1222 |
| 1207 global_->field_trial_allocator_.reset( | 1223 global_->field_trial_allocator_.reset( |
| 1208 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); | 1224 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false)); |
| 1209 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); | 1225 global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName); |
| 1210 | 1226 |
| 1211 // Add all existing field trials. | 1227 // Add all existing field trials. |
| 1212 for (const auto& registered : global_->registered_) { | 1228 for (const auto& registered : global_->registered_) { |
| 1213 AddToAllocatorWhileLocked(registered.second); | 1229 AddToAllocatorWhileLocked(registered.second); |
| 1214 } | 1230 } |
| 1215 | 1231 |
| 1216 // Add all existing features. | 1232 // Add all existing features. |
| 1217 FeatureList::GetInstance()->AddFeaturesToAllocator( | 1233 FeatureList::GetInstance()->AddFeaturesToAllocator( |
| 1218 global_->field_trial_allocator_.get()); | 1234 global_->field_trial_allocator_.get()); |
| 1219 | 1235 |
| 1220 #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) | 1236 #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 | 1237 // Set |readonly_allocator_handle_| so we can pass it to be inherited and |
| 1222 // via the command line. | 1238 // via the command line. |
| 1223 global_->readonly_allocator_handle_ = | 1239 global_->readonly_allocator_handle_ = |
| 1224 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); | 1240 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); |
| 1225 #endif | 1241 #endif |
| 1226 } | 1242 } |
| 1227 #endif | 1243 #endif |
| 1228 | 1244 |
| 1229 // static | 1245 // static |
| 1230 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { | 1246 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1325 return; | 1341 return; |
| 1326 } | 1342 } |
| 1327 AutoLock auto_lock(global_->lock_); | 1343 AutoLock auto_lock(global_->lock_); |
| 1328 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1344 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
| 1329 trial->AddRef(); | 1345 trial->AddRef(); |
| 1330 trial->SetTrialRegistered(); | 1346 trial->SetTrialRegistered(); |
| 1331 global_->registered_[trial->trial_name()] = trial; | 1347 global_->registered_[trial->trial_name()] = trial; |
| 1332 } | 1348 } |
| 1333 | 1349 |
| 1334 } // namespace base | 1350 } // namespace base |
| OLD | NEW |