Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(113)

Side by Side Diff: base/metrics/field_trial.cc

Issue 2862123002: Pass the GUID for the SharedMemoryHandle used by base::FieldTrialList. (Closed)
Patch Set: clang format Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698