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" |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
201 cmd_line->AppendSwitchASCII(disable_features_switch, disabled_features); | 201 cmd_line->AppendSwitchASCII(disable_features_switch, disabled_features); |
202 | 202 |
203 std::string field_trial_states; | 203 std::string field_trial_states; |
204 FieldTrialList::AllStatesToString(&field_trial_states); | 204 FieldTrialList::AllStatesToString(&field_trial_states); |
205 if (!field_trial_states.empty()) { | 205 if (!field_trial_states.empty()) { |
206 cmd_line->AppendSwitchASCII(switches::kForceFieldTrials, | 206 cmd_line->AppendSwitchASCII(switches::kForceFieldTrials, |
207 field_trial_states); | 207 field_trial_states); |
208 } | 208 } |
209 } | 209 } |
210 | 210 |
211 #if defined(OS_WIN) | |
212 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { | |
213 HANDLE src = allocator->shared_memory()->handle().GetHandle(); | |
214 ProcessHandle process = GetCurrentProcess(); | |
215 DWORD access = SECTION_MAP_READ | SECTION_QUERY; | |
216 HANDLE dst; | |
217 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) | |
218 return kInvalidPlatformFile; | |
219 return dst; | |
220 } | |
221 #endif | |
222 | |
223 #if defined(OS_POSIX) && !defined(OS_NACL) | |
224 int CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { | |
225 SharedMemoryHandle handle = allocator->shared_memory()->GetReadOnlyHandle(); | |
226 return SharedMemory::GetFdFromSharedMemoryHandle(handle); | |
227 } | |
228 #endif | |
229 | |
230 void OnOutOfMemory(size_t size) { | 211 void OnOutOfMemory(size_t size) { |
231 #if defined(OS_NACL) | 212 #if defined(OS_NACL) |
232 NOTREACHED(); | 213 NOTREACHED(); |
233 #else | 214 #else |
234 TerminateBecauseOutOfMemory(size); | 215 TerminateBecauseOutOfMemory(size); |
235 #endif | 216 #endif |
236 } | 217 } |
237 | 218 |
238 } // namespace | 219 } // namespace |
239 | 220 |
(...skipping 528 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
768 // processes are properly reported in crash reports. | 749 // processes are properly reported in crash reports. |
769 trial->group(); | 750 trial->group(); |
770 } | 751 } |
771 } | 752 } |
772 return true; | 753 return true; |
773 } | 754 } |
774 | 755 |
775 // static | 756 // static |
776 void FieldTrialList::CreateTrialsFromCommandLine( | 757 void FieldTrialList::CreateTrialsFromCommandLine( |
777 const CommandLine& cmd_line, | 758 const CommandLine& cmd_line, |
778 const char* field_trial_handle_switch, | 759 const char* field_trial_switch_value, |
779 int fd_key) { | 760 int fd_key) { |
780 global_->create_trials_from_command_line_called_ = true; | 761 global_->create_trials_from_command_line_called_ = true; |
781 | 762 |
782 #if defined(OS_WIN) | 763 #if defined(OS_WIN) |
783 if (cmd_line.HasSwitch(field_trial_handle_switch)) { | 764 if (cmd_line.HasSwitch(field_trial_switch_value)) { |
784 std::string handle_switch = | 765 std::string switch_value = |
785 cmd_line.GetSwitchValueASCII(field_trial_handle_switch); | 766 cmd_line.GetSwitchValueASCII(field_trial_switch_value); |
786 bool result = CreateTrialsFromHandleSwitch(handle_switch); | 767 bool result = CreateTrialsFromSwitchValue(switch_value); |
787 DCHECK(result); | 768 DCHECK(result); |
788 } | 769 } |
789 #endif | 770 #endif |
790 | 771 |
791 #if defined(OS_POSIX) && !defined(OS_NACL) | 772 #if defined(OS_POSIX) && !defined(OS_NACL) |
792 // On POSIX, we check if the handle is valid by seeing if the browser process | 773 // On POSIX, we check if the handle is valid by seeing if the browser process |
793 // sent over the switch (we don't care about the value). Invalid handles | 774 // sent over the switch (we don't care about the value). Invalid handles |
794 // occur in some browser tests which don't initialize the allocator. | 775 // occur in some browser tests which don't initialize the allocator. |
795 if (cmd_line.HasSwitch(field_trial_handle_switch)) { | 776 if (cmd_line.HasSwitch(field_trial_switch_value)) { |
796 bool result = CreateTrialsFromDescriptor(fd_key); | 777 std::string switch_value = |
778 cmd_line.GetSwitchValueASCII(field_trial_switch_value); | |
779 bool result = CreateTrialsFromDescriptor(fd_key, switch_value); | |
797 DCHECK(result); | 780 DCHECK(result); |
798 } | 781 } |
799 #endif | 782 #endif |
800 | 783 |
801 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { | 784 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) { |
802 bool result = FieldTrialList::CreateTrialsFromString( | 785 bool result = FieldTrialList::CreateTrialsFromString( |
803 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), | 786 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials), |
804 std::set<std::string>()); | 787 std::set<std::string>()); |
805 DCHECK(result); | 788 DCHECK(result); |
806 } | 789 } |
(...skipping 18 matching lines...) Expand all Loading... | |
825 } | 808 } |
826 | 809 |
827 #if defined(OS_WIN) | 810 #if defined(OS_WIN) |
828 // static | 811 // static |
829 void FieldTrialList::AppendFieldTrialHandleIfNeeded( | 812 void FieldTrialList::AppendFieldTrialHandleIfNeeded( |
830 HandlesToInheritVector* handles) { | 813 HandlesToInheritVector* handles) { |
831 if (!global_) | 814 if (!global_) |
832 return; | 815 return; |
833 if (kUseSharedMemoryForFieldTrials) { | 816 if (kUseSharedMemoryForFieldTrials) { |
834 InstantiateFieldTrialAllocatorIfNeeded(); | 817 InstantiateFieldTrialAllocatorIfNeeded(); |
835 if (global_->readonly_allocator_handle_) | 818 if (global_->readonly_allocator_handle_.IsValid()) |
836 handles->push_back(global_->readonly_allocator_handle_); | 819 handles->push_back(global_->readonly_allocator_handle_.GetHandle()); |
837 } | 820 } |
838 } | 821 } |
839 #endif | 822 #endif |
840 | 823 |
841 #if defined(OS_POSIX) && !defined(OS_NACL) | 824 #if defined(OS_POSIX) && !defined(OS_NACL) |
842 // static | 825 // static |
843 int FieldTrialList::GetFieldTrialHandle() { | 826 SharedMemoryHandle FieldTrialList::GetFieldTrialHandle() { |
844 if (global_ && kUseSharedMemoryForFieldTrials) { | 827 if (global_ && kUseSharedMemoryForFieldTrials) { |
845 InstantiateFieldTrialAllocatorIfNeeded(); | 828 InstantiateFieldTrialAllocatorIfNeeded(); |
846 // We check for an invalid handle where this gets called. | 829 // We check for an invalid handle where this gets called. |
847 return global_->readonly_allocator_handle_; | 830 return global_->readonly_allocator_handle_; |
848 } | 831 } |
849 return kInvalidPlatformFile; | 832 return SharedMemoryHandle(); |
850 } | 833 } |
851 #endif | 834 #endif |
852 | 835 |
853 // static | 836 // static |
854 void FieldTrialList::CopyFieldTrialStateToFlags( | 837 void FieldTrialList::CopyFieldTrialStateToFlags( |
855 const char* field_trial_handle_switch, | 838 const char* field_trial_switch_value, |
Alexei Svitkine (slow)
2017/05/05 18:02:16
It's not the switch value - it's the switch name..
erikchen
2017/05/05 19:41:51
sed error.
| |
856 const char* enable_features_switch, | 839 const char* enable_features_switch, |
857 const char* disable_features_switch, | 840 const char* disable_features_switch, |
858 CommandLine* cmd_line) { | 841 CommandLine* cmd_line) { |
859 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, | 842 // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, |
860 // content browser tests currently don't create a FieldTrialList because they | 843 // content browser tests currently don't create a FieldTrialList because they |
861 // don't run ChromeBrowserMainParts code where it's done for Chrome. | 844 // don't run ChromeBrowserMainParts code where it's done for Chrome. |
862 // Some tests depend on the enable and disable features flag switch, though, | 845 // Some tests depend on the enable and disable features flag switch, though, |
863 // so we can still add those even though AllStatesToString() will be a no-op. | 846 // so we can still add those even though AllStatesToString() will be a no-op. |
864 if (!global_) { | 847 if (!global_) { |
865 AddFeatureAndFieldTrialFlags(enable_features_switch, | 848 AddFeatureAndFieldTrialFlags(enable_features_switch, |
866 disable_features_switch, cmd_line); | 849 disable_features_switch, cmd_line); |
867 return; | 850 return; |
868 } | 851 } |
869 | 852 |
870 // Use shared memory to pass the state if the feature is enabled, otherwise | 853 // Use shared memory to pass the state if the feature is enabled, otherwise |
871 // fallback to passing it via the command line as a string. | 854 // fallback to passing it via the command line as a string. |
872 if (kUseSharedMemoryForFieldTrials) { | 855 if (kUseSharedMemoryForFieldTrials) { |
873 InstantiateFieldTrialAllocatorIfNeeded(); | 856 InstantiateFieldTrialAllocatorIfNeeded(); |
874 // If the readonly handle didn't get duplicated properly, then fallback to | 857 // If the readonly handle didn't get duplicated properly, then fallback to |
875 // original behavior. | 858 // original behavior. |
876 if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) { | 859 if (!global_->readonly_allocator_handle_.IsValid()) { |
877 AddFeatureAndFieldTrialFlags(enable_features_switch, | 860 AddFeatureAndFieldTrialFlags(enable_features_switch, |
878 disable_features_switch, cmd_line); | 861 disable_features_switch, cmd_line); |
879 return; | 862 return; |
880 } | 863 } |
881 | 864 |
882 global_->field_trial_allocator_->UpdateTrackingHistograms(); | 865 global_->field_trial_allocator_->UpdateTrackingHistograms(); |
883 | 866 std::string switch_value = SerializeSharedMemoryHandleMetadata( |
884 #if defined(OS_WIN) | 867 global_->readonly_allocator_handle_); |
885 // We need to pass a named anonymous handle to shared memory over the | 868 cmd_line->AppendSwitchASCII(field_trial_switch_value, switch_value); |
886 // command line on Windows, since the child doesn't know which of the | |
887 // handles it inherited it should open. | |
888 // PlatformFile is typedef'd to HANDLE which is typedef'd to void *. We | |
889 // basically cast the handle into an int (uintptr_t, to be exact), stringify | |
890 // the int, and pass it as a command-line flag. The child process will do | |
891 // the reverse conversions to retrieve the handle. See | |
892 // http://stackoverflow.com/a/153077 | |
893 auto uintptr_handle = | |
894 reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_); | |
895 std::string field_trial_handle = std::to_string(uintptr_handle); | |
896 cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle); | |
897 #elif defined(OS_POSIX) | |
898 // On POSIX, we dup the fd into a fixed fd kFieldTrialDescriptor, so we | |
899 // don't have to pass over the handle (it's not even the right handle | |
900 // anyways). But some browser tests don't create the allocator, so we need | |
901 // to be able to distinguish valid and invalid handles. We do that by just | |
902 // checking that the flag is set with a dummy value. | |
903 cmd_line->AppendSwitchASCII(field_trial_handle_switch, "1"); | |
904 #else | |
905 #error Unsupported OS | |
906 #endif | |
907 return; | 869 return; |
908 } | 870 } |
909 | 871 |
910 AddFeatureAndFieldTrialFlags(enable_features_switch, disable_features_switch, | 872 AddFeatureAndFieldTrialFlags(enable_features_switch, disable_features_switch, |
911 cmd_line); | 873 cmd_line); |
912 } | 874 } |
913 | 875 |
914 // static | 876 // static |
915 FieldTrial* FieldTrialList::CreateFieldTrial( | 877 FieldTrial* FieldTrialList::CreateFieldTrial( |
916 const std::string& name, | 878 const std::string& name, |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1125 std::vector<const FieldTrial::FieldTrialEntry*> entries; | 1087 std::vector<const FieldTrial::FieldTrialEntry*> entries; |
1126 FieldTrialAllocator::Iterator iter(&allocator); | 1088 FieldTrialAllocator::Iterator iter(&allocator); |
1127 const FieldTrial::FieldTrialEntry* entry; | 1089 const FieldTrial::FieldTrialEntry* entry; |
1128 while ((entry = iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) != | 1090 while ((entry = iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) != |
1129 nullptr) { | 1091 nullptr) { |
1130 entries.push_back(entry); | 1092 entries.push_back(entry); |
1131 } | 1093 } |
1132 return entries; | 1094 return entries; |
1133 } | 1095 } |
1134 | 1096 |
1097 // static | |
1098 std::string FieldTrialList::SerializeSharedMemoryHandleMetadata( | |
1099 const SharedMemoryHandle& shm) { | |
1100 std::stringstream ss; | |
1101 #if defined(OS_WIN) | |
1102 // Tell the child process the name of the inherited HANDLE. | |
1103 uintptr_t uintptr_handle = reinterpret_cast<uintptr_t>(shm.GetHandle()); | |
1104 ss << uintptr_handle << ","; | |
1105 #elif !defined(OS_POSIX) | |
1106 #error Unsupported OS | |
1107 #endif | |
1108 | |
1109 base::UnguessableToken guid = shm.GetGUID(); | |
1110 ss << guid.GetHighForSerialization() << "," << guid.GetLowForSerialization(); | |
1111 return ss.str(); | |
1112 } | |
1113 | |
1135 #if defined(OS_WIN) | 1114 #if defined(OS_WIN) |
1136 // static | 1115 // static |
1137 bool FieldTrialList::CreateTrialsFromHandleSwitch( | 1116 SharedMemoryHandle FieldTrialList::DeserializeSharedMemoryHandleMetadata( |
1138 const std::string& handle_switch) { | 1117 const std::string& switch_value) { |
1139 int field_trial_handle = std::stoi(handle_switch); | 1118 std::istringstream iss(switch_value); |
1119 std::string token; | |
1120 | |
1121 std::getline(iss, token, ','); | |
Avi (use Gerrit)
2017/05/05 04:30:12
You use base::StringToInt, why not base::SplitStri
Alexei Svitkine (slow)
2017/05/05 18:02:16
+1 - let's use SplitString()
erikchen
2017/05/05 19:41:51
Done.
| |
1122 int field_trial_handle = 0; | |
1123 if (!base::StringToInt(token, &field_trial_handle)) | |
1124 return SharedMemoryHandle(); | |
1140 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle); | 1125 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle); |
1141 // TODO(erikchen): Plumb a GUID for this SharedMemoryHandle. | 1126 |
1142 // https://crbug.com/713763. | 1127 std::getline(iss, token, ','); |
1143 SharedMemoryHandle shm_handle(handle, base::UnguessableToken::Create()); | 1128 uint64_t high = 0; |
1144 return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle); | 1129 if (!base::StringToUint64(token, &high)) |
1130 return SharedMemoryHandle(); | |
1131 std::getline(iss, token, ','); | |
1132 uint64_t low = 0; | |
1133 if (!base::StringToUint64(token, &low)) | |
1134 return SharedMemoryHandle(); | |
1135 | |
1136 base::UnguessableToken guid = base::UnguessableToken::Deserialize(high, low); | |
1137 return SharedMemoryHandle(handle, guid); | |
1138 } | |
1139 | |
1140 // static | |
1141 bool FieldTrialList::CreateTrialsFromSwitchValue( | |
1142 const std::string& switch_value) { | |
1143 SharedMemoryHandle shm = DeserializeSharedMemoryHandleMetadata(switch_value); | |
1144 if (!shm.IsValid()) | |
1145 return false; | |
1146 return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm); | |
1145 } | 1147 } |
1146 #endif | 1148 #endif |
1147 | 1149 |
1148 #if defined(OS_POSIX) && !defined(OS_NACL) | 1150 #if defined(OS_POSIX) && !defined(OS_NACL) |
1149 // static | 1151 // static |
1150 bool FieldTrialList::CreateTrialsFromDescriptor(int fd_key) { | 1152 SharedMemoryHandle FieldTrialList::DeserializeSharedMemoryHandleMetadata( |
1153 int fd, | |
1154 const std::string& switch_value) { | |
Alexei Svitkine (slow)
2017/05/05 18:02:16
How about unifying the code for the windows and po
erikchen
2017/05/05 19:41:51
I thought about this - there needs to be another i
| |
1155 std::istringstream iss(switch_value); | |
1156 std::string token; | |
1157 std::getline(iss, token, ','); | |
1158 uint64_t high = 0; | |
1159 if (!base::StringToUint64(token, &high)) | |
1160 return SharedMemoryHandle(); | |
1161 std::getline(iss, token, ','); | |
1162 uint64_t low = 0; | |
1163 if (!base::StringToUint64(token, &low)) | |
1164 return SharedMemoryHandle(); | |
1165 | |
1166 base::UnguessableToken guid = base::UnguessableToken::Deserialize(high, low); | |
1167 return SharedMemoryHandle(FileDescriptor(fd, true), guid); | |
1168 } | |
1169 | |
1170 // static | |
1171 bool FieldTrialList::CreateTrialsFromDescriptor( | |
1172 int fd_key, | |
1173 const std::string& switch_value) { | |
1151 if (!kUseSharedMemoryForFieldTrials) | 1174 if (!kUseSharedMemoryForFieldTrials) |
1152 return false; | 1175 return false; |
1153 | 1176 |
1154 if (fd_key == -1) | 1177 if (fd_key == -1) |
1155 return false; | 1178 return false; |
1156 | 1179 |
1157 int fd = GlobalDescriptors::GetInstance()->MaybeGet(fd_key); | 1180 int fd = GlobalDescriptors::GetInstance()->MaybeGet(fd_key); |
1158 if (fd == -1) | 1181 if (fd == -1) |
1159 return false; | 1182 return false; |
1160 | 1183 |
1161 // TODO(erikchen): Plumb a GUID for this SharedMemoryHandle. | 1184 SharedMemoryHandle shm = |
1162 // https://crbug.com/713763. | 1185 DeserializeSharedMemoryHandleMetadata(fd, switch_value); |
1163 SharedMemoryHandle shm_handle(FileDescriptor(fd, true), | 1186 if (!shm.IsValid()) |
1164 base::UnguessableToken::Create()); | 1187 return false; |
1165 | 1188 |
1166 bool result = FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle); | 1189 bool result = FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm); |
1167 DCHECK(result); | 1190 DCHECK(result); |
1168 return true; | 1191 return true; |
1169 } | 1192 } |
1170 #endif | 1193 #endif |
1171 | 1194 |
1172 // static | 1195 // static |
1173 bool FieldTrialList::CreateTrialsFromSharedMemoryHandle( | 1196 bool FieldTrialList::CreateTrialsFromSharedMemoryHandle( |
1174 SharedMemoryHandle shm_handle) { | 1197 SharedMemoryHandle shm_handle) { |
1175 // shm gets deleted when it gets out of scope, but that's OK because we need | 1198 // shm gets deleted when it gets out of scope, but that's OK because we need |
1176 // it only for the duration of this method. | 1199 // it only for the duration of this method. |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1247 } | 1270 } |
1248 | 1271 |
1249 // Add all existing features. | 1272 // Add all existing features. |
1250 FeatureList::GetInstance()->AddFeaturesToAllocator( | 1273 FeatureList::GetInstance()->AddFeaturesToAllocator( |
1251 global_->field_trial_allocator_.get()); | 1274 global_->field_trial_allocator_.get()); |
1252 | 1275 |
1253 #if !defined(OS_NACL) | 1276 #if !defined(OS_NACL) |
1254 // Set |readonly_allocator_handle_| so we can pass it to be inherited and | 1277 // Set |readonly_allocator_handle_| so we can pass it to be inherited and |
1255 // via the command line. | 1278 // via the command line. |
1256 global_->readonly_allocator_handle_ = | 1279 global_->readonly_allocator_handle_ = |
1257 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); | 1280 global_->field_trial_allocator_->shared_memory()->GetReadOnlyHandle(); |
1258 #endif | 1281 #endif |
1259 } | 1282 } |
1260 | 1283 |
1261 // static | 1284 // static |
1262 void FieldTrialList::AddToAllocatorWhileLocked( | 1285 void FieldTrialList::AddToAllocatorWhileLocked( |
1263 PersistentMemoryAllocator* allocator, | 1286 PersistentMemoryAllocator* allocator, |
1264 FieldTrial* field_trial) { | 1287 FieldTrial* field_trial) { |
1265 // Don't do anything if the allocator hasn't been instantiated yet. | 1288 // Don't do anything if the allocator hasn't been instantiated yet. |
1266 if (allocator == nullptr) | 1289 if (allocator == nullptr) |
1267 return; | 1290 return; |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1359 return; | 1382 return; |
1360 } | 1383 } |
1361 AutoLock auto_lock(global_->lock_); | 1384 AutoLock auto_lock(global_->lock_); |
1362 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1385 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
1363 trial->AddRef(); | 1386 trial->AddRef(); |
1364 trial->SetTrialRegistered(); | 1387 trial->SetTrialRegistered(); |
1365 global_->registered_[trial->trial_name()] = trial; | 1388 global_->registered_[trial->trial_name()] = trial; |
1366 } | 1389 } |
1367 | 1390 |
1368 } // namespace base | 1391 } // namespace base |
OLD | NEW |