Unwind the URL-based experiment IDs.
[chromium-blink-merge.git] / chrome / browser / supervised_user / supervised_user_whitelist_service.cc
blob73840c7f171a7bce42c54bdc895b9edda9f8c5d4
1 // Copyright 2014 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.
5 #include "chrome/browser/supervised_user/supervised_user_whitelist_service.h"
7 #include <string>
9 #include "base/files/file_path.h"
10 #include "base/metrics/histogram.h"
11 #include "base/metrics/user_metrics.h"
12 #include "base/metrics/user_metrics_action.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/prefs/scoped_user_pref_update.h"
15 #include "base/values.h"
16 #include "chrome/browser/component_updater/supervised_user_whitelist_installer.h"
17 #include "chrome/browser/supervised_user/supervised_user_site_list.h"
18 #include "chrome/common/pref_names.h"
19 #include "components/pref_registry/pref_registry_syncable.h"
20 #include "sync/api/sync_change.h"
21 #include "sync/api/sync_data.h"
22 #include "sync/api/sync_error.h"
23 #include "sync/api/sync_error_factory.h"
24 #include "sync/api/sync_merge_result.h"
25 #include "sync/protocol/sync.pb.h"
27 const char kName[] = "name";
29 SupervisedUserWhitelistService::SupervisedUserWhitelistService(
30 PrefService* prefs,
31 component_updater::SupervisedUserWhitelistInstaller* installer,
32 const std::string& client_id)
33 : prefs_(prefs),
34 installer_(installer),
35 client_id_(client_id),
36 weak_ptr_factory_(this) {
37 DCHECK(prefs);
40 SupervisedUserWhitelistService::~SupervisedUserWhitelistService() {
43 // static
44 void SupervisedUserWhitelistService::RegisterProfilePrefs(
45 user_prefs::PrefRegistrySyncable* registry) {
46 registry->RegisterDictionaryPref(
47 prefs::kSupervisedUserWhitelists,
48 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
51 void SupervisedUserWhitelistService::Init() {
52 const base::DictionaryValue* whitelists =
53 prefs_->GetDictionary(prefs::kSupervisedUserWhitelists);
54 for (base::DictionaryValue::Iterator it(*whitelists); !it.IsAtEnd();
55 it.Advance()) {
56 registered_whitelists_.insert(it.key());
58 UMA_HISTOGRAM_COUNTS_100("ManagedUsers.Whitelist.Count", whitelists->size());
60 // The installer can be null in some unit tests.
61 if (!installer_)
62 return;
64 installer_->Subscribe(
65 base::Bind(&SupervisedUserWhitelistService::OnWhitelistReady,
66 weak_ptr_factory_.GetWeakPtr()));
69 void SupervisedUserWhitelistService::AddSiteListsChangedCallback(
70 const SiteListsChangedCallback& callback) {
71 site_lists_changed_callbacks_.push_back(callback);
73 std::vector<scoped_refptr<SupervisedUserSiteList>> whitelists;
74 GetLoadedWhitelists(&whitelists);
75 callback.Run(whitelists);
78 void SupervisedUserWhitelistService::LoadWhitelistForTesting(
79 const std::string& id,
80 const base::FilePath& path) {
81 bool result = registered_whitelists_.insert(id).second;
82 DCHECK(result);
83 OnWhitelistReady(id, path);
86 void SupervisedUserWhitelistService::UnloadWhitelist(const std::string& id) {
87 bool result = registered_whitelists_.erase(id) > 0u;
88 DCHECK(result);
89 loaded_whitelists_.erase(id);
90 NotifyWhitelistsChanged();
93 // static
94 syncer::SyncData SupervisedUserWhitelistService::CreateWhitelistSyncData(
95 const std::string& id,
96 const std::string& name) {
97 sync_pb::EntitySpecifics specifics;
98 sync_pb::ManagedUserWhitelistSpecifics* whitelist =
99 specifics.mutable_managed_user_whitelist();
100 whitelist->set_id(id);
101 whitelist->set_name(name);
103 return syncer::SyncData::CreateLocalData(id, name, specifics);
106 syncer::SyncMergeResult
107 SupervisedUserWhitelistService::MergeDataAndStartSyncing(
108 syncer::ModelType type,
109 const syncer::SyncDataList& initial_sync_data,
110 scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
111 scoped_ptr<syncer::SyncErrorFactory> error_handler) {
112 DCHECK_EQ(syncer::SUPERVISED_USER_WHITELISTS, type);
114 syncer::SyncChangeList change_list;
115 syncer::SyncMergeResult result(syncer::SUPERVISED_USER_WHITELISTS);
117 DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUserWhitelists);
118 base::DictionaryValue* pref_dict = update.Get();
119 result.set_num_items_before_association(pref_dict->size());
120 std::set<std::string> seen_ids;
121 int num_items_added = 0;
122 int num_items_modified = 0;
124 for (const syncer::SyncData& sync_data : initial_sync_data) {
125 DCHECK_EQ(syncer::SUPERVISED_USER_WHITELISTS, sync_data.GetDataType());
126 const sync_pb::ManagedUserWhitelistSpecifics& whitelist =
127 sync_data.GetSpecifics().managed_user_whitelist();
128 std::string id = whitelist.id();
129 std::string name = whitelist.name();
130 seen_ids.insert(id);
131 base::DictionaryValue* dict = nullptr;
132 if (pref_dict->GetDictionary(id, &dict)) {
133 std::string old_name;
134 bool result = dict->GetString(kName, &old_name);
135 DCHECK(result);
136 if (name != old_name) {
137 SetWhitelistProperties(dict, whitelist);
138 num_items_modified++;
140 } else {
141 num_items_added++;
142 AddNewWhitelist(pref_dict, whitelist);
146 std::set<std::string> ids_to_remove;
147 for (base::DictionaryValue::Iterator it(*pref_dict); !it.IsAtEnd();
148 it.Advance()) {
149 if (seen_ids.find(it.key()) == seen_ids.end())
150 ids_to_remove.insert(it.key());
153 for (const std::string& id : ids_to_remove)
154 RemoveWhitelist(pref_dict, id);
156 // Notify if whitelists have been uninstalled. We will notify about newly
157 // added whitelists later, when they are actually available
158 // (in OnWhitelistLoaded).
159 if (!ids_to_remove.empty())
160 NotifyWhitelistsChanged();
162 result.set_num_items_added(num_items_added);
163 result.set_num_items_modified(num_items_modified);
164 result.set_num_items_deleted(ids_to_remove.size());
165 result.set_num_items_after_association(pref_dict->size());
166 return result;
169 void SupervisedUserWhitelistService::StopSyncing(syncer::ModelType type) {
170 DCHECK_EQ(syncer::SUPERVISED_USER_WHITELISTS, type);
173 syncer::SyncDataList SupervisedUserWhitelistService::GetAllSyncData(
174 syncer::ModelType type) const {
175 syncer::SyncDataList sync_data;
176 const base::DictionaryValue* whitelists =
177 prefs_->GetDictionary(prefs::kSupervisedUserWhitelists);
178 for (base::DictionaryValue::Iterator it(*whitelists); !it.IsAtEnd();
179 it.Advance()) {
180 const std::string& id = it.key();
181 const base::DictionaryValue* dict = nullptr;
182 it.value().GetAsDictionary(&dict);
183 std::string name;
184 bool result = dict->GetString(kName, &name);
185 DCHECK(result);
186 sync_pb::EntitySpecifics specifics;
187 sync_pb::ManagedUserWhitelistSpecifics* whitelist =
188 specifics.mutable_managed_user_whitelist();
189 whitelist->set_id(id);
190 whitelist->set_name(name);
191 sync_data.push_back(syncer::SyncData::CreateLocalData(id, name, specifics));
193 return sync_data;
196 syncer::SyncError SupervisedUserWhitelistService::ProcessSyncChanges(
197 const tracked_objects::Location& from_here,
198 const syncer::SyncChangeList& change_list) {
199 bool whitelists_removed = false;
200 syncer::SyncError error;
201 DictionaryPrefUpdate update(prefs_, prefs::kSupervisedUserWhitelists);
202 base::DictionaryValue* pref_dict = update.Get();
203 for (const syncer::SyncChange& sync_change : change_list) {
204 syncer::SyncData data = sync_change.sync_data();
205 DCHECK_EQ(syncer::SUPERVISED_USER_WHITELISTS, data.GetDataType());
206 const sync_pb::ManagedUserWhitelistSpecifics& whitelist =
207 data.GetSpecifics().managed_user_whitelist();
208 std::string id = whitelist.id();
209 switch (sync_change.change_type()) {
210 case syncer::SyncChange::ACTION_ADD: {
211 DCHECK(!pref_dict->HasKey(id)) << id;
212 AddNewWhitelist(pref_dict, whitelist);
213 break;
215 case syncer::SyncChange::ACTION_UPDATE: {
216 base::DictionaryValue* dict = nullptr;
217 pref_dict->GetDictionaryWithoutPathExpansion(id, &dict);
218 SetWhitelistProperties(dict, whitelist);
219 break;
221 case syncer::SyncChange::ACTION_DELETE: {
222 DCHECK(pref_dict->HasKey(id)) << id;
223 RemoveWhitelist(pref_dict, id);
224 whitelists_removed = true;
225 break;
227 case syncer::SyncChange::ACTION_INVALID: {
228 NOTREACHED();
229 break;
234 if (whitelists_removed)
235 NotifyWhitelistsChanged();
237 return error;
240 void SupervisedUserWhitelistService::AddNewWhitelist(
241 base::DictionaryValue* pref_dict,
242 const sync_pb::ManagedUserWhitelistSpecifics& whitelist) {
243 base::RecordAction(base::UserMetricsAction("ManagedUsers_Whitelist_Added"));
245 bool new_installation = true;
246 RegisterWhitelist(whitelist.id(), whitelist.name(), new_installation);
247 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
248 SetWhitelistProperties(dict.get(), whitelist);
249 pref_dict->SetWithoutPathExpansion(whitelist.id(), dict.release());
252 void SupervisedUserWhitelistService::SetWhitelistProperties(
253 base::DictionaryValue* dict,
254 const sync_pb::ManagedUserWhitelistSpecifics& whitelist) {
255 dict->SetString(kName, whitelist.name());
258 void SupervisedUserWhitelistService::RemoveWhitelist(
259 base::DictionaryValue* pref_dict,
260 const std::string& id) {
261 base::RecordAction(base::UserMetricsAction("ManagedUsers_Whitelist_Removed"));
263 pref_dict->RemoveWithoutPathExpansion(id, NULL);
264 installer_->UnregisterWhitelist(client_id_, id);
265 UnloadWhitelist(id);
268 void SupervisedUserWhitelistService::RegisterWhitelist(const std::string& id,
269 const std::string& name,
270 bool new_installation) {
271 bool result = registered_whitelists_.insert(id).second;
272 DCHECK(result);
274 installer_->RegisterWhitelist(client_id_, id, name);
277 void SupervisedUserWhitelistService::GetLoadedWhitelists(
278 std::vector<scoped_refptr<SupervisedUserSiteList>>* whitelists) {
279 for (const auto& whitelist : loaded_whitelists_)
280 whitelists->push_back(whitelist.second);
283 void SupervisedUserWhitelistService::NotifyWhitelistsChanged() {
284 std::vector<scoped_refptr<SupervisedUserSiteList>> whitelists;
285 GetLoadedWhitelists(&whitelists);
287 for (const auto& callback : site_lists_changed_callbacks_)
288 callback.Run(whitelists);
291 void SupervisedUserWhitelistService::OnWhitelistReady(
292 const std::string& id,
293 const base::FilePath& whitelist_path) {
294 // If we did not register the whitelist or it has been unregistered in the
295 // mean time, ignore it.
296 if (registered_whitelists_.count(id) == 0u)
297 return;
299 SupervisedUserSiteList::Load(
300 whitelist_path,
301 base::Bind(&SupervisedUserWhitelistService::OnWhitelistLoaded,
302 weak_ptr_factory_.GetWeakPtr(), id, base::TimeTicks::Now()));
305 void SupervisedUserWhitelistService::OnWhitelistLoaded(
306 const std::string& id,
307 base::TimeTicks start_time,
308 const scoped_refptr<SupervisedUserSiteList>& whitelist) {
309 if (!whitelist) {
310 LOG(WARNING) << "Couldn't load whitelist " << id;
311 return;
314 UMA_HISTOGRAM_TIMES("ManagedUsers.Whitelist.TotalLoadDuration",
315 base::TimeTicks::Now() - start_time);
317 // If the whitelist has been unregistered in the mean time, ignore it.
318 if (registered_whitelists_.count(id) == 0u)
319 return;
321 loaded_whitelists_[id] = whitelist;
322 NotifyWhitelistsChanged();