1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/variations/synthetic_trial_registry.h"
6 
7 #include "base/stl_util.h"
8 
9 namespace variations {
10 
11 SyntheticTrialRegistry::SyntheticTrialRegistry() = default;
12 SyntheticTrialRegistry::~SyntheticTrialRegistry() = default;
13 
AddSyntheticTrialObserver(SyntheticTrialObserver * observer)14 void SyntheticTrialRegistry::AddSyntheticTrialObserver(
15     SyntheticTrialObserver* observer) {
16   synthetic_trial_observer_list_.AddObserver(observer);
17   if (!synthetic_trial_groups_.empty())
18     observer->OnSyntheticTrialsChanged(synthetic_trial_groups_);
19 }
20 
RemoveSyntheticTrialObserver(SyntheticTrialObserver * observer)21 void SyntheticTrialRegistry::RemoveSyntheticTrialObserver(
22     SyntheticTrialObserver* observer) {
23   synthetic_trial_observer_list_.RemoveObserver(observer);
24 }
25 
RegisterSyntheticFieldTrial(const SyntheticTrialGroup & trial)26 void SyntheticTrialRegistry::RegisterSyntheticFieldTrial(
27     const SyntheticTrialGroup& trial) {
28   for (size_t i = 0; i < synthetic_trial_groups_.size(); ++i) {
29     if (synthetic_trial_groups_[i].id.name == trial.id.name) {
30       if (synthetic_trial_groups_[i].id.group != trial.id.group) {
31         synthetic_trial_groups_[i].id.group = trial.id.group;
32         synthetic_trial_groups_[i].start_time = base::TimeTicks::Now();
33         NotifySyntheticTrialObservers();
34       }
35       return;
36     }
37   }
38 
39   SyntheticTrialGroup trial_group = trial;
40   trial_group.start_time = base::TimeTicks::Now();
41   synthetic_trial_groups_.push_back(trial_group);
42   NotifySyntheticTrialObservers();
43 }
44 
RegisterSyntheticMultiGroupFieldTrial(uint32_t trial_name_hash,const std::vector<uint32_t> & group_name_hashes)45 void SyntheticTrialRegistry::RegisterSyntheticMultiGroupFieldTrial(
46     uint32_t trial_name_hash,
47     const std::vector<uint32_t>& group_name_hashes) {
48   auto has_same_trial_name = [trial_name_hash](const SyntheticTrialGroup& x) {
49     return x.id.name == trial_name_hash;
50   };
51   base::EraseIf(synthetic_trial_groups_, has_same_trial_name);
52 
53   if (group_name_hashes.empty())
54     return;
55 
56   SyntheticTrialGroup trial_group(trial_name_hash, group_name_hashes[0]);
57   trial_group.start_time = base::TimeTicks::Now();
58   for (uint32_t group_name_hash : group_name_hashes) {
59     // Note: Adding the trial group will copy it, so this re-uses the same
60     // |trial_group| struct for convenience (e.g. so start_time's all match).
61     trial_group.id.group = group_name_hash;
62     synthetic_trial_groups_.push_back(trial_group);
63   }
64   NotifySyntheticTrialObservers();
65 }
66 
NotifySyntheticTrialObservers()67 void SyntheticTrialRegistry::NotifySyntheticTrialObservers() {
68   for (SyntheticTrialObserver& observer : synthetic_trial_observer_list_) {
69     observer.OnSyntheticTrialsChanged(synthetic_trial_groups_);
70   }
71 }
72 
GetSyntheticFieldTrialsOlderThan(base::TimeTicks time,std::vector<ActiveGroupId> * synthetic_trials)73 void SyntheticTrialRegistry::GetSyntheticFieldTrialsOlderThan(
74     base::TimeTicks time,
75     std::vector<ActiveGroupId>* synthetic_trials) {
76   DCHECK(synthetic_trials);
77   synthetic_trials->clear();
78   for (size_t i = 0; i < synthetic_trial_groups_.size(); ++i) {
79     if (synthetic_trial_groups_[i].start_time <= time)
80       synthetic_trials->push_back(synthetic_trial_groups_[i].id);
81   }
82 }
83 
84 }  // namespace variations
85