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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 // shared memory segment). See https://codereview.chromium.org/2365273004/ and | 48 // shared memory segment). See https://codereview.chromium.org/2365273004/ and |
49 // crbug.com/653874 | 49 // crbug.com/653874 |
50 // The browser is the only process that has write access to the shared memory. | 50 // The browser is the only process that has write access to the shared memory. |
51 // This is safe from race conditions because MakeIterable is a release operation | 51 // This is safe from race conditions because MakeIterable is a release operation |
52 // and GetNextOfType is an acquire operation, so memory writes before | 52 // and GetNextOfType is an acquire operation, so memory writes before |
53 // MakeIterable happen before memory reads after GetNextOfType. | 53 // MakeIterable happen before memory reads after GetNextOfType. |
54 const bool kUseSharedMemoryForFieldTrials = true; | 54 const bool kUseSharedMemoryForFieldTrials = true; |
55 | 55 |
56 // Constants for the field trial allocator. | 56 // Constants for the field trial allocator. |
57 const char kAllocatorName[] = "FieldTrialAllocator"; | 57 const char kAllocatorName[] = "FieldTrialAllocator"; |
58 const uint32_t kFieldTrialType = 0xABA17E13 + 2; // SHA1(FieldTrialEntry) v2 | |
59 | 58 |
60 // We allocate 128 KiB to hold all the field trial data. This should be enough, | 59 // We allocate 128 KiB to hold all the field trial data. This should be enough, |
61 // as most people use 3 - 25 KiB for field trials (as of 11/25/2016). | 60 // as most people use 3 - 25 KiB for field trials (as of 11/25/2016). |
62 // This also doesn't allocate all 128 KiB at once -- the pages only get mapped | 61 // This also doesn't allocate all 128 KiB at once -- the pages only get mapped |
63 // to physical memory when they are touched. If the size of the allocated field | 62 // to physical memory when they are touched. If the size of the allocated field |
64 // trials does get larger than 128 KiB, then we will drop some field trials in | 63 // trials does get larger than 128 KiB, then we will drop some field trials in |
65 // child processes, leading to an inconsistent view between browser and child | 64 // child processes, leading to an inconsistent view between browser and child |
66 // processes and possibly causing crashes (see crbug.com/661617). | 65 // processes and possibly causing crashes (see crbug.com/661617). |
67 #if !defined(OS_NACL) | 66 #if !defined(OS_NACL) |
68 const size_t kFieldTrialAllocationSize = 128 << 10; // 128 KiB | 67 const size_t kFieldTrialAllocationSize = 128 << 10; // 128 KiB |
(...skipping 641 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
710 | 709 |
711 if (!global_->field_trial_allocator_) { | 710 if (!global_->field_trial_allocator_) { |
712 GetActiveFieldTrialGroupsFromString( | 711 GetActiveFieldTrialGroupsFromString( |
713 command_line.GetSwitchValueASCII(switches::kForceFieldTrials), | 712 command_line.GetSwitchValueASCII(switches::kForceFieldTrials), |
714 active_groups); | 713 active_groups); |
715 return; | 714 return; |
716 } | 715 } |
717 | 716 |
718 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); | 717 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); |
719 FieldTrialAllocator::Iterator mem_iter(allocator); | 718 FieldTrialAllocator::Iterator mem_iter(allocator); |
720 FieldTrial::FieldTrialRef ref; | 719 const FieldTrial::FieldTrialEntry* entry; |
721 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) != | 720 while ((entry = mem_iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) != |
722 SharedPersistentMemoryAllocator::kReferenceNull) { | 721 nullptr) { |
723 const FieldTrial::FieldTrialEntry* entry = | |
724 allocator->GetAsObject<const FieldTrial::FieldTrialEntry>( | |
725 ref, kFieldTrialType); | |
726 | |
727 StringPiece trial_name; | 722 StringPiece trial_name; |
728 StringPiece group_name; | 723 StringPiece group_name; |
729 if (subtle::NoBarrier_Load(&entry->activated) && | 724 if (subtle::NoBarrier_Load(&entry->activated) && |
730 entry->GetTrialAndGroupName(&trial_name, &group_name)) { | 725 entry->GetTrialAndGroupName(&trial_name, &group_name)) { |
731 FieldTrial::ActiveGroup group; | 726 FieldTrial::ActiveGroup group; |
732 group.trial_name = trial_name.as_string(); | 727 group.trial_name = trial_name.as_string(); |
733 group.group_name = group_name.as_string(); | 728 group.group_name = group_name.as_string(); |
734 active_groups->push_back(group); | 729 active_groups->push_back(group); |
735 } | 730 } |
736 } | 731 } |
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1035 // you can call it after it's been set up. | 1030 // you can call it after it's been set up. |
1036 AutoLock auto_lock(global_->lock_); | 1031 AutoLock auto_lock(global_->lock_); |
1037 if (!global_->field_trial_allocator_) | 1032 if (!global_->field_trial_allocator_) |
1038 return false; | 1033 return false; |
1039 | 1034 |
1040 // If ref_ isn't set, then the field trial data can't be in shared memory. | 1035 // If ref_ isn't set, then the field trial data can't be in shared memory. |
1041 if (!field_trial->ref_) | 1036 if (!field_trial->ref_) |
1042 return false; | 1037 return false; |
1043 | 1038 |
1044 const FieldTrial::FieldTrialEntry* entry = | 1039 const FieldTrial::FieldTrialEntry* entry = |
1045 global_->field_trial_allocator_ | 1040 global_->field_trial_allocator_->GetAsObject<FieldTrial::FieldTrialEntry>( |
1046 ->GetAsObject<const FieldTrial::FieldTrialEntry>(field_trial->ref_, | 1041 field_trial->ref_); |
1047 kFieldTrialType); | |
1048 | 1042 |
1049 size_t allocated_size = | 1043 size_t allocated_size = |
1050 global_->field_trial_allocator_->GetAllocSize(field_trial->ref_); | 1044 global_->field_trial_allocator_->GetAllocSize(field_trial->ref_); |
1051 size_t actual_size = sizeof(FieldTrial::FieldTrialEntry) + entry->pickle_size; | 1045 size_t actual_size = sizeof(FieldTrial::FieldTrialEntry) + entry->pickle_size; |
1052 if (allocated_size < actual_size) | 1046 if (allocated_size < actual_size) |
1053 return false; | 1047 return false; |
1054 | 1048 |
1055 return entry->GetParams(params); | 1049 return entry->GetParams(params); |
1056 } | 1050 } |
1057 | 1051 |
(...skipping 10 matching lines...) Expand all Loading... |
1068 // just the trial and group name into a newly-allocated segment and then clear | 1062 // just the trial and group name into a newly-allocated segment and then clear |
1069 // the existing item. | 1063 // the existing item. |
1070 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); | 1064 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); |
1071 FieldTrialAllocator::Iterator mem_iter(allocator); | 1065 FieldTrialAllocator::Iterator mem_iter(allocator); |
1072 | 1066 |
1073 // List of refs to eventually be made iterable. We can't make it in the loop, | 1067 // List of refs to eventually be made iterable. We can't make it in the loop, |
1074 // since it would go on forever. | 1068 // since it would go on forever. |
1075 std::vector<FieldTrial::FieldTrialRef> new_refs; | 1069 std::vector<FieldTrial::FieldTrialRef> new_refs; |
1076 | 1070 |
1077 FieldTrial::FieldTrialRef prev_ref; | 1071 FieldTrial::FieldTrialRef prev_ref; |
1078 while ((prev_ref = mem_iter.GetNextOfType(kFieldTrialType)) != | 1072 while ((prev_ref = mem_iter.GetNextOfType<FieldTrial::FieldTrialEntry>()) != |
1079 FieldTrialAllocator::kReferenceNull) { | 1073 FieldTrialAllocator::kReferenceNull) { |
1080 // Get the existing field trial entry in shared memory. | 1074 // Get the existing field trial entry in shared memory. |
1081 const FieldTrial::FieldTrialEntry* prev_entry = | 1075 const FieldTrial::FieldTrialEntry* prev_entry = |
1082 allocator->GetAsObject<const FieldTrial::FieldTrialEntry>( | 1076 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(prev_ref); |
1083 prev_ref, kFieldTrialType); | |
1084 StringPiece trial_name; | 1077 StringPiece trial_name; |
1085 StringPiece group_name; | 1078 StringPiece group_name; |
1086 if (!prev_entry->GetTrialAndGroupName(&trial_name, &group_name)) | 1079 if (!prev_entry->GetTrialAndGroupName(&trial_name, &group_name)) |
1087 continue; | 1080 continue; |
1088 | 1081 |
1089 // Write a new entry, minus the params. | 1082 // Write a new entry, minus the params. |
1090 Pickle pickle; | 1083 Pickle pickle; |
1091 pickle.WriteString(trial_name); | 1084 pickle.WriteString(trial_name); |
1092 pickle.WriteString(group_name); | 1085 pickle.WriteString(group_name); |
1093 size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size(); | 1086 size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size(); |
1094 FieldTrial::FieldTrialRef new_ref = | |
1095 allocator->Allocate(total_size, kFieldTrialType); | |
1096 FieldTrial::FieldTrialEntry* new_entry = | 1087 FieldTrial::FieldTrialEntry* new_entry = |
1097 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(new_ref, | 1088 allocator->AllocateObject<FieldTrial::FieldTrialEntry>(total_size); |
1098 kFieldTrialType); | |
1099 subtle::NoBarrier_Store(&new_entry->activated, | 1089 subtle::NoBarrier_Store(&new_entry->activated, |
1100 subtle::NoBarrier_Load(&prev_entry->activated)); | 1090 subtle::NoBarrier_Load(&prev_entry->activated)); |
1101 new_entry->pickle_size = pickle.size(); | 1091 new_entry->pickle_size = pickle.size(); |
1102 | 1092 |
1103 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section | 1093 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section |
1104 // in memory, so we can avoid this memcpy. | 1094 // in memory, so we can avoid this memcpy. |
1105 char* dst = reinterpret_cast<char*>(new_entry) + | 1095 char* dst = reinterpret_cast<char*>(new_entry) + |
1106 sizeof(FieldTrial::FieldTrialEntry); | 1096 sizeof(FieldTrial::FieldTrialEntry); |
1107 memcpy(dst, pickle.data(), pickle.size()); | 1097 memcpy(dst, pickle.data(), pickle.size()); |
1108 | 1098 |
1109 // Update the ref on the field trial and add it to the list to be made | 1099 // Update the ref on the field trial and add it to the list to be made |
1110 // iterable. | 1100 // iterable. |
| 1101 FieldTrial::FieldTrialRef new_ref = allocator->GetAsReference(new_entry); |
1111 FieldTrial* trial = global_->PreLockedFind(trial_name.as_string()); | 1102 FieldTrial* trial = global_->PreLockedFind(trial_name.as_string()); |
1112 trial->ref_ = new_ref; | 1103 trial->ref_ = new_ref; |
1113 new_refs.push_back(new_ref); | 1104 new_refs.push_back(new_ref); |
1114 | 1105 |
1115 // Mark the existing entry as unused. | 1106 // Mark the existing entry as unused. |
1116 allocator->ChangeType(prev_ref, 0, kFieldTrialType); | 1107 allocator->ChangeType(prev_ref, 0, |
| 1108 FieldTrial::FieldTrialEntry::kPersistentTypeId); |
1117 } | 1109 } |
1118 | 1110 |
1119 for (const auto& ref : new_refs) { | 1111 for (const auto& ref : new_refs) { |
1120 allocator->MakeIterable(ref); | 1112 allocator->MakeIterable(ref); |
1121 } | 1113 } |
1122 } | 1114 } |
1123 | 1115 |
1124 // static | 1116 // static |
1125 void FieldTrialList::DumpAllFieldTrialsToPersistentAllocator( | 1117 void FieldTrialList::DumpAllFieldTrialsToPersistentAllocator( |
1126 PersistentMemoryAllocator* allocator) { | 1118 PersistentMemoryAllocator* allocator) { |
1127 if (!global_) | 1119 if (!global_) |
1128 return; | 1120 return; |
1129 AutoLock auto_lock(global_->lock_); | 1121 AutoLock auto_lock(global_->lock_); |
1130 for (const auto& registered : global_->registered_) { | 1122 for (const auto& registered : global_->registered_) { |
1131 AddToAllocatorWhileLocked(allocator, registered.second); | 1123 AddToAllocatorWhileLocked(allocator, registered.second); |
1132 } | 1124 } |
1133 } | 1125 } |
1134 | 1126 |
1135 // static | 1127 // static |
1136 std::vector<const FieldTrial::FieldTrialEntry*> | 1128 std::vector<const FieldTrial::FieldTrialEntry*> |
1137 FieldTrialList::GetAllFieldTrialsFromPersistentAllocator( | 1129 FieldTrialList::GetAllFieldTrialsFromPersistentAllocator( |
1138 PersistentMemoryAllocator const& allocator) { | 1130 PersistentMemoryAllocator const& allocator) { |
1139 std::vector<const FieldTrial::FieldTrialEntry*> entries; | 1131 std::vector<const FieldTrial::FieldTrialEntry*> entries; |
1140 FieldTrial::FieldTrialRef ref; | |
1141 FieldTrialAllocator::Iterator iter(&allocator); | 1132 FieldTrialAllocator::Iterator iter(&allocator); |
1142 while ((ref = iter.GetNextOfType(kFieldTrialType)) != | 1133 const FieldTrial::FieldTrialEntry* entry; |
1143 FieldTrialAllocator::kReferenceNull) { | 1134 while ((entry = iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) != |
1144 const FieldTrial::FieldTrialEntry* entry = | 1135 nullptr) { |
1145 allocator.GetAsObject<const FieldTrial::FieldTrialEntry>( | |
1146 ref, kFieldTrialType); | |
1147 entries.push_back(entry); | 1136 entries.push_back(entry); |
1148 } | 1137 } |
1149 return entries; | 1138 return entries; |
1150 } | 1139 } |
1151 | 1140 |
1152 #if defined(OS_WIN) | 1141 #if defined(OS_WIN) |
1153 // static | 1142 // static |
1154 bool FieldTrialList::CreateTrialsFromHandleSwitch( | 1143 bool FieldTrialList::CreateTrialsFromHandleSwitch( |
1155 const std::string& handle_switch) { | 1144 const std::string& handle_switch) { |
1156 int field_trial_handle = std::stoi(handle_switch); | 1145 int field_trial_handle = std::stoi(handle_switch); |
(...skipping 18 matching lines...) Expand all Loading... |
1175 #endif | 1164 #endif |
1176 | 1165 |
1177 // static | 1166 // static |
1178 bool FieldTrialList::CreateTrialsFromSharedMemory( | 1167 bool FieldTrialList::CreateTrialsFromSharedMemory( |
1179 std::unique_ptr<SharedMemory> shm) { | 1168 std::unique_ptr<SharedMemory> shm) { |
1180 global_->field_trial_allocator_.reset( | 1169 global_->field_trial_allocator_.reset( |
1181 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, true)); | 1170 new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, true)); |
1182 FieldTrialAllocator* shalloc = global_->field_trial_allocator_.get(); | 1171 FieldTrialAllocator* shalloc = global_->field_trial_allocator_.get(); |
1183 FieldTrialAllocator::Iterator mem_iter(shalloc); | 1172 FieldTrialAllocator::Iterator mem_iter(shalloc); |
1184 | 1173 |
1185 FieldTrial::FieldTrialRef ref; | 1174 const FieldTrial::FieldTrialEntry* entry; |
1186 while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) != | 1175 while ((entry = mem_iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) != |
1187 FieldTrialAllocator::kReferenceNull) { | 1176 nullptr) { |
1188 const FieldTrial::FieldTrialEntry* entry = | |
1189 shalloc->GetAsObject<const FieldTrial::FieldTrialEntry>( | |
1190 ref, kFieldTrialType); | |
1191 | |
1192 StringPiece trial_name; | 1177 StringPiece trial_name; |
1193 StringPiece group_name; | 1178 StringPiece group_name; |
1194 if (!entry->GetTrialAndGroupName(&trial_name, &group_name)) | 1179 if (!entry->GetTrialAndGroupName(&trial_name, &group_name)) |
1195 return false; | 1180 return false; |
1196 | 1181 |
1197 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take | 1182 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take |
1198 // StringPieces. | 1183 // StringPieces. |
1199 FieldTrial* trial = | 1184 FieldTrial* trial = |
1200 CreateFieldTrial(trial_name.as_string(), group_name.as_string()); | 1185 CreateFieldTrial(trial_name.as_string(), group_name.as_string()); |
1201 | 1186 |
1202 trial->ref_ = ref; | 1187 trial->ref_ = mem_iter.GetAsReference(entry); |
1203 if (subtle::NoBarrier_Load(&entry->activated)) { | 1188 if (subtle::NoBarrier_Load(&entry->activated)) { |
1204 // Call |group()| to mark the trial as "used" and notify observers, if | 1189 // Call |group()| to mark the trial as "used" and notify observers, if |
1205 // any. This is useful to ensure that field trials created in child | 1190 // any. This is useful to ensure that field trials created in child |
1206 // processes are properly reported in crash reports. | 1191 // processes are properly reported in crash reports. |
1207 trial->group(); | 1192 trial->group(); |
1208 } | 1193 } |
1209 } | 1194 } |
1210 return true; | 1195 return true; |
1211 } | 1196 } |
1212 | 1197 |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1279 if (field_trial->ref_) | 1264 if (field_trial->ref_) |
1280 return; | 1265 return; |
1281 | 1266 |
1282 Pickle pickle; | 1267 Pickle pickle; |
1283 if (!PickleFieldTrial(trial_state, &pickle)) { | 1268 if (!PickleFieldTrial(trial_state, &pickle)) { |
1284 NOTREACHED(); | 1269 NOTREACHED(); |
1285 return; | 1270 return; |
1286 } | 1271 } |
1287 | 1272 |
1288 size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size(); | 1273 size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size(); |
1289 FieldTrial::FieldTrialRef ref = | 1274 FieldTrial::FieldTrialRef ref = allocator->Allocate( |
1290 allocator->Allocate(total_size, kFieldTrialType); | 1275 total_size, FieldTrial::FieldTrialEntry::kPersistentTypeId); |
1291 if (ref == FieldTrialAllocator::kReferenceNull) { | 1276 if (ref == FieldTrialAllocator::kReferenceNull) { |
1292 NOTREACHED(); | 1277 NOTREACHED(); |
1293 return; | 1278 return; |
1294 } | 1279 } |
1295 | 1280 |
1296 FieldTrial::FieldTrialEntry* entry = | 1281 FieldTrial::FieldTrialEntry* entry = |
1297 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref, kFieldTrialType); | 1282 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref); |
1298 subtle::NoBarrier_Store(&entry->activated, trial_state.activated); | 1283 subtle::NoBarrier_Store(&entry->activated, trial_state.activated); |
1299 entry->pickle_size = pickle.size(); | 1284 entry->pickle_size = pickle.size(); |
1300 | 1285 |
1301 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section in | 1286 // TODO(lawrencewu): Modify base::Pickle to be able to write over a section in |
1302 // memory, so we can avoid this memcpy. | 1287 // memory, so we can avoid this memcpy. |
1303 char* dst = | 1288 char* dst = |
1304 reinterpret_cast<char*>(entry) + sizeof(FieldTrial::FieldTrialEntry); | 1289 reinterpret_cast<char*>(entry) + sizeof(FieldTrial::FieldTrialEntry); |
1305 memcpy(dst, pickle.data(), pickle.size()); | 1290 memcpy(dst, pickle.data(), pickle.size()); |
1306 | 1291 |
1307 allocator->MakeIterable(ref); | 1292 allocator->MakeIterable(ref); |
(...skipping 13 matching lines...) Expand all Loading... |
1321 if (ref == FieldTrialAllocator::kReferenceNull) { | 1306 if (ref == FieldTrialAllocator::kReferenceNull) { |
1322 // It's fine to do this even if the allocator hasn't been instantiated | 1307 // It's fine to do this even if the allocator hasn't been instantiated |
1323 // yet -- it'll just return early. | 1308 // yet -- it'll just return early. |
1324 AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(), | 1309 AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(), |
1325 field_trial); | 1310 field_trial); |
1326 } else { | 1311 } else { |
1327 // It's also okay to do this even though the callee doesn't have a lock -- | 1312 // It's also okay to do this even though the callee doesn't have a lock -- |
1328 // the only thing that happens on a stale read here is a slight performance | 1313 // the only thing that happens on a stale read here is a slight performance |
1329 // hit from the child re-synchronizing activation state. | 1314 // hit from the child re-synchronizing activation state. |
1330 FieldTrial::FieldTrialEntry* entry = | 1315 FieldTrial::FieldTrialEntry* entry = |
1331 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref, | 1316 allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref); |
1332 kFieldTrialType); | |
1333 subtle::NoBarrier_Store(&entry->activated, 1); | 1317 subtle::NoBarrier_Store(&entry->activated, 1); |
1334 } | 1318 } |
1335 } | 1319 } |
1336 | 1320 |
1337 // static | 1321 // static |
1338 const FieldTrial::EntropyProvider* | 1322 const FieldTrial::EntropyProvider* |
1339 FieldTrialList::GetEntropyProviderForOneTimeRandomization() { | 1323 FieldTrialList::GetEntropyProviderForOneTimeRandomization() { |
1340 if (!global_) { | 1324 if (!global_) { |
1341 used_without_global_ = true; | 1325 used_without_global_ = true; |
1342 return NULL; | 1326 return NULL; |
(...skipping 16 matching lines...) Expand all Loading... |
1359 return; | 1343 return; |
1360 } | 1344 } |
1361 AutoLock auto_lock(global_->lock_); | 1345 AutoLock auto_lock(global_->lock_); |
1362 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1346 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
1363 trial->AddRef(); | 1347 trial->AddRef(); |
1364 trial->SetTrialRegistered(); | 1348 trial->SetTrialRegistered(); |
1365 global_->registered_[trial->trial_name()] = trial; | 1349 global_->registered_[trial->trial_name()] = trial; |
1366 } | 1350 } |
1367 | 1351 |
1368 } // namespace base | 1352 } // namespace base |
OLD | NEW |