OLD | NEW |
| (Empty) |
1 // Copyright 2013 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 "chrome/browser/managed_mode/managed_user_settings_service.h" | |
6 | |
7 #include "base/callback.h" | |
8 #include "base/json/json_reader.h" | |
9 #include "base/json/json_writer.h" | |
10 #include "base/prefs/json_pref_store.h" | |
11 #include "base/prefs/pref_filter.h" | |
12 #include "base/strings/string_util.h" | |
13 #include "base/threading/sequenced_worker_pool.h" | |
14 #include "chrome/browser/managed_mode/managed_mode_url_filter.h" | |
15 #include "chrome/common/chrome_constants.h" | |
16 #include "content/public/browser/browser_thread.h" | |
17 #include "content/public/browser/user_metrics.h" | |
18 #include "sync/api/sync_change.h" | |
19 #include "sync/api/sync_error_factory.h" | |
20 #include "sync/protocol/sync.pb.h" | |
21 | |
22 using base::DictionaryValue; | |
23 using base::JSONReader; | |
24 using base::UserMetricsAction; | |
25 using base::Value; | |
26 using content::BrowserThread; | |
27 using syncer::SUPERVISED_USER_SETTINGS; | |
28 using syncer::ModelType; | |
29 using syncer::SyncChange; | |
30 using syncer::SyncChangeList; | |
31 using syncer::SyncChangeProcessor; | |
32 using syncer::SyncData; | |
33 using syncer::SyncDataList; | |
34 using syncer::SyncError; | |
35 using syncer::SyncErrorFactory; | |
36 using syncer::SyncMergeResult; | |
37 | |
38 const char kAtomicSettings[] = "atomic_settings"; | |
39 const char kManagedUserInternalItemPrefix[] = "X-"; | |
40 const char kQueuedItems[] = "queued_items"; | |
41 const char kSplitSettingKeySeparator = ':'; | |
42 const char kSplitSettings[] = "split_settings"; | |
43 | |
44 namespace { | |
45 | |
46 bool SettingShouldApplyToPrefs(const std::string& name) { | |
47 return !StartsWithASCII(name, kManagedUserInternalItemPrefix, false); | |
48 } | |
49 | |
50 } // namespace | |
51 | |
52 ManagedUserSettingsService::ManagedUserSettingsService() | |
53 : active_(false), local_settings_(new base::DictionaryValue) {} | |
54 | |
55 ManagedUserSettingsService::~ManagedUserSettingsService() {} | |
56 | |
57 void ManagedUserSettingsService::Init( | |
58 base::FilePath profile_path, | |
59 base::SequencedTaskRunner* sequenced_task_runner, | |
60 bool load_synchronously) { | |
61 base::FilePath path = | |
62 profile_path.Append(chrome::kSupervisedUserSettingsFilename); | |
63 PersistentPrefStore* store = new JsonPrefStore( | |
64 path, sequenced_task_runner, scoped_ptr<PrefFilter>()); | |
65 Init(store); | |
66 if (load_synchronously) | |
67 store_->ReadPrefs(); | |
68 else | |
69 store_->ReadPrefsAsync(NULL); | |
70 } | |
71 | |
72 void ManagedUserSettingsService::Init( | |
73 scoped_refptr<PersistentPrefStore> store) { | |
74 DCHECK(!store_); | |
75 store_ = store; | |
76 store_->AddObserver(this); | |
77 } | |
78 | |
79 void ManagedUserSettingsService::Subscribe(const SettingsCallback& callback) { | |
80 if (IsReady()) { | |
81 scoped_ptr<base::DictionaryValue> settings = GetSettings(); | |
82 callback.Run(settings.get()); | |
83 } | |
84 | |
85 subscribers_.push_back(callback); | |
86 } | |
87 | |
88 void ManagedUserSettingsService::SetActive(bool active) { | |
89 active_ = active; | |
90 InformSubscribers(); | |
91 } | |
92 | |
93 bool ManagedUserSettingsService::IsReady() { | |
94 return store_->IsInitializationComplete(); | |
95 } | |
96 | |
97 void ManagedUserSettingsService::Clear() { | |
98 store_->RemoveValue(kAtomicSettings); | |
99 store_->RemoveValue(kSplitSettings); | |
100 } | |
101 | |
102 // static | |
103 std::string ManagedUserSettingsService::MakeSplitSettingKey( | |
104 const std::string& prefix, | |
105 const std::string& key) { | |
106 return prefix + kSplitSettingKeySeparator + key; | |
107 } | |
108 | |
109 void ManagedUserSettingsService::UploadItem(const std::string& key, | |
110 scoped_ptr<base::Value> value) { | |
111 DCHECK(!SettingShouldApplyToPrefs(key)); | |
112 | |
113 std::string key_suffix = key; | |
114 base::DictionaryValue* dict = NULL; | |
115 if (sync_processor_) { | |
116 content::RecordAction(UserMetricsAction("ManagedUsers_UploadItem_Syncing")); | |
117 dict = GetDictionaryAndSplitKey(&key_suffix); | |
118 DCHECK(GetQueuedItems()->empty()); | |
119 SyncChangeList change_list; | |
120 SyncData data = CreateSyncDataForSetting(key, *value); | |
121 SyncChange::SyncChangeType change_type = | |
122 dict->HasKey(key_suffix) ? SyncChange::ACTION_UPDATE | |
123 : SyncChange::ACTION_ADD; | |
124 change_list.push_back(SyncChange(FROM_HERE, change_type, data)); | |
125 SyncError error = | |
126 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list); | |
127 DCHECK(!error.IsSet()) << error.ToString(); | |
128 } else { | |
129 // Queue the item up to be uploaded when we start syncing | |
130 // (in MergeDataAndStartSyncing()). | |
131 content::RecordAction(UserMetricsAction("ManagedUsers_UploadItem_Queued")); | |
132 dict = GetQueuedItems(); | |
133 } | |
134 dict->SetWithoutPathExpansion(key_suffix, value.release()); | |
135 } | |
136 | |
137 void ManagedUserSettingsService::SetLocalSettingForTesting( | |
138 const std::string& key, | |
139 scoped_ptr<base::Value> value) { | |
140 if (value) | |
141 local_settings_->SetWithoutPathExpansion(key, value.release()); | |
142 else | |
143 local_settings_->RemoveWithoutPathExpansion(key, NULL); | |
144 | |
145 InformSubscribers(); | |
146 } | |
147 | |
148 // static | |
149 SyncData ManagedUserSettingsService::CreateSyncDataForSetting( | |
150 const std::string& name, | |
151 const base::Value& value) { | |
152 std::string json_value; | |
153 base::JSONWriter::Write(&value, &json_value); | |
154 ::sync_pb::EntitySpecifics specifics; | |
155 specifics.mutable_managed_user_setting()->set_name(name); | |
156 specifics.mutable_managed_user_setting()->set_value(json_value); | |
157 return SyncData::CreateLocalData(name, name, specifics); | |
158 } | |
159 | |
160 void ManagedUserSettingsService::Shutdown() { | |
161 store_->RemoveObserver(this); | |
162 } | |
163 | |
164 SyncMergeResult ManagedUserSettingsService::MergeDataAndStartSyncing( | |
165 ModelType type, | |
166 const SyncDataList& initial_sync_data, | |
167 scoped_ptr<SyncChangeProcessor> sync_processor, | |
168 scoped_ptr<SyncErrorFactory> error_handler) { | |
169 DCHECK_EQ(SUPERVISED_USER_SETTINGS, type); | |
170 sync_processor_ = sync_processor.Pass(); | |
171 error_handler_ = error_handler.Pass(); | |
172 | |
173 // Clear all atomic and split settings, then recreate them from Sync data. | |
174 Clear(); | |
175 for (SyncDataList::const_iterator it = initial_sync_data.begin(); | |
176 it != initial_sync_data.end(); ++it) { | |
177 DCHECK_EQ(SUPERVISED_USER_SETTINGS, it->GetDataType()); | |
178 const ::sync_pb::ManagedUserSettingSpecifics& managed_user_setting = | |
179 it->GetSpecifics().managed_user_setting(); | |
180 scoped_ptr<base::Value> value( | |
181 JSONReader::Read(managed_user_setting.value())); | |
182 std::string name_suffix = managed_user_setting.name(); | |
183 base::DictionaryValue* dict = GetDictionaryAndSplitKey(&name_suffix); | |
184 dict->SetWithoutPathExpansion(name_suffix, value.release()); | |
185 } | |
186 store_->ReportValueChanged(kAtomicSettings); | |
187 store_->ReportValueChanged(kSplitSettings); | |
188 InformSubscribers(); | |
189 | |
190 // Upload all the queued up items (either with an ADD or an UPDATE action, | |
191 // depending on whether they already exist) and move them to split settings. | |
192 SyncChangeList change_list; | |
193 base::DictionaryValue* queued_items = GetQueuedItems(); | |
194 for (base::DictionaryValue::Iterator it(*queued_items); !it.IsAtEnd(); | |
195 it.Advance()) { | |
196 std::string key_suffix = it.key(); | |
197 base::DictionaryValue* dict = GetDictionaryAndSplitKey(&key_suffix); | |
198 SyncData data = CreateSyncDataForSetting(it.key(), it.value()); | |
199 SyncChange::SyncChangeType change_type = | |
200 dict->HasKey(key_suffix) ? SyncChange::ACTION_UPDATE | |
201 : SyncChange::ACTION_ADD; | |
202 change_list.push_back(SyncChange(FROM_HERE, change_type, data)); | |
203 dict->SetWithoutPathExpansion(key_suffix, it.value().DeepCopy()); | |
204 } | |
205 queued_items->Clear(); | |
206 | |
207 SyncMergeResult result(SUPERVISED_USER_SETTINGS); | |
208 // Process all the accumulated changes from the queued items. | |
209 if (change_list.size() > 0) { | |
210 store_->ReportValueChanged(kQueuedItems); | |
211 result.set_error( | |
212 sync_processor_->ProcessSyncChanges(FROM_HERE, change_list)); | |
213 } | |
214 | |
215 // TODO(bauerb): Statistics? | |
216 return result; | |
217 } | |
218 | |
219 void ManagedUserSettingsService::StopSyncing(ModelType type) { | |
220 DCHECK_EQ(syncer::SUPERVISED_USER_SETTINGS, type); | |
221 sync_processor_.reset(); | |
222 error_handler_.reset(); | |
223 } | |
224 | |
225 SyncDataList ManagedUserSettingsService::GetAllSyncData( | |
226 ModelType type) const { | |
227 DCHECK_EQ(syncer::SUPERVISED_USER_SETTINGS, type); | |
228 SyncDataList data; | |
229 for (base::DictionaryValue::Iterator it(*GetAtomicSettings()); !it.IsAtEnd(); | |
230 it.Advance()) { | |
231 data.push_back(CreateSyncDataForSetting(it.key(), it.value())); | |
232 } | |
233 for (base::DictionaryValue::Iterator it(*GetSplitSettings()); !it.IsAtEnd(); | |
234 it.Advance()) { | |
235 const base::DictionaryValue* dict = NULL; | |
236 it.value().GetAsDictionary(&dict); | |
237 for (base::DictionaryValue::Iterator jt(*dict); | |
238 !jt.IsAtEnd(); jt.Advance()) { | |
239 data.push_back(CreateSyncDataForSetting( | |
240 MakeSplitSettingKey(it.key(), jt.key()), jt.value())); | |
241 } | |
242 } | |
243 DCHECK_EQ(0u, GetQueuedItems()->size()); | |
244 return data; | |
245 } | |
246 | |
247 SyncError ManagedUserSettingsService::ProcessSyncChanges( | |
248 const tracked_objects::Location& from_here, | |
249 const SyncChangeList& change_list) { | |
250 for (SyncChangeList::const_iterator it = change_list.begin(); | |
251 it != change_list.end(); ++it) { | |
252 SyncData data = it->sync_data(); | |
253 DCHECK_EQ(SUPERVISED_USER_SETTINGS, data.GetDataType()); | |
254 const ::sync_pb::ManagedUserSettingSpecifics& managed_user_setting = | |
255 data.GetSpecifics().managed_user_setting(); | |
256 std::string key = managed_user_setting.name(); | |
257 base::DictionaryValue* dict = GetDictionaryAndSplitKey(&key); | |
258 switch (it->change_type()) { | |
259 case SyncChange::ACTION_ADD: | |
260 case SyncChange::ACTION_UPDATE: { | |
261 scoped_ptr<base::Value> value( | |
262 JSONReader::Read(managed_user_setting.value())); | |
263 if (dict->HasKey(key)) { | |
264 DLOG_IF(WARNING, it->change_type() == SyncChange::ACTION_ADD) | |
265 << "Value for key " << key << " already exists"; | |
266 } else { | |
267 DLOG_IF(WARNING, it->change_type() == SyncChange::ACTION_UPDATE) | |
268 << "Value for key " << key << " doesn't exist yet"; | |
269 } | |
270 dict->SetWithoutPathExpansion(key, value.release()); | |
271 break; | |
272 } | |
273 case SyncChange::ACTION_DELETE: { | |
274 DLOG_IF(WARNING, !dict->HasKey(key)) << "Trying to delete nonexistent " | |
275 << "key " << key; | |
276 dict->RemoveWithoutPathExpansion(key, NULL); | |
277 break; | |
278 } | |
279 case SyncChange::ACTION_INVALID: { | |
280 NOTREACHED(); | |
281 break; | |
282 } | |
283 } | |
284 } | |
285 store_->ReportValueChanged(kAtomicSettings); | |
286 store_->ReportValueChanged(kSplitSettings); | |
287 InformSubscribers(); | |
288 | |
289 SyncError error; | |
290 return error; | |
291 } | |
292 | |
293 void ManagedUserSettingsService::OnPrefValueChanged(const std::string& key) {} | |
294 | |
295 void ManagedUserSettingsService::OnInitializationCompleted(bool success) { | |
296 DCHECK(success); | |
297 DCHECK(IsReady()); | |
298 InformSubscribers(); | |
299 } | |
300 | |
301 base::DictionaryValue* ManagedUserSettingsService::GetOrCreateDictionary( | |
302 const std::string& key) const { | |
303 base::Value* value = NULL; | |
304 base::DictionaryValue* dict = NULL; | |
305 if (store_->GetMutableValue(key, &value)) { | |
306 bool success = value->GetAsDictionary(&dict); | |
307 DCHECK(success); | |
308 } else { | |
309 dict = new base::DictionaryValue; | |
310 store_->SetValue(key, dict); | |
311 } | |
312 | |
313 return dict; | |
314 } | |
315 | |
316 base::DictionaryValue* ManagedUserSettingsService::GetAtomicSettings() const { | |
317 return GetOrCreateDictionary(kAtomicSettings); | |
318 } | |
319 | |
320 base::DictionaryValue* ManagedUserSettingsService::GetSplitSettings() const { | |
321 return GetOrCreateDictionary(kSplitSettings); | |
322 } | |
323 | |
324 base::DictionaryValue* ManagedUserSettingsService::GetQueuedItems() const { | |
325 return GetOrCreateDictionary(kQueuedItems); | |
326 } | |
327 | |
328 base::DictionaryValue* ManagedUserSettingsService::GetDictionaryAndSplitKey( | |
329 std::string* key) const { | |
330 size_t pos = key->find_first_of(kSplitSettingKeySeparator); | |
331 if (pos == std::string::npos) | |
332 return GetAtomicSettings(); | |
333 | |
334 base::DictionaryValue* split_settings = GetSplitSettings(); | |
335 std::string prefix = key->substr(0, pos); | |
336 base::DictionaryValue* dict = NULL; | |
337 if (!split_settings->GetDictionary(prefix, &dict)) { | |
338 dict = new base::DictionaryValue; | |
339 DCHECK(!split_settings->HasKey(prefix)); | |
340 split_settings->Set(prefix, dict); | |
341 } | |
342 key->erase(0, pos + 1); | |
343 return dict; | |
344 } | |
345 | |
346 scoped_ptr<base::DictionaryValue> ManagedUserSettingsService::GetSettings() { | |
347 DCHECK(IsReady()); | |
348 if (!active_) | |
349 return scoped_ptr<base::DictionaryValue>(); | |
350 | |
351 scoped_ptr<base::DictionaryValue> settings(local_settings_->DeepCopy()); | |
352 | |
353 base::DictionaryValue* atomic_settings = GetAtomicSettings(); | |
354 for (base::DictionaryValue::Iterator it(*atomic_settings); !it.IsAtEnd(); | |
355 it.Advance()) { | |
356 if (!SettingShouldApplyToPrefs(it.key())) | |
357 continue; | |
358 | |
359 settings->Set(it.key(), it.value().DeepCopy()); | |
360 } | |
361 | |
362 base::DictionaryValue* split_settings = GetSplitSettings(); | |
363 for (base::DictionaryValue::Iterator it(*split_settings); !it.IsAtEnd(); | |
364 it.Advance()) { | |
365 if (!SettingShouldApplyToPrefs(it.key())) | |
366 continue; | |
367 | |
368 settings->Set(it.key(), it.value().DeepCopy()); | |
369 } | |
370 | |
371 return settings.Pass(); | |
372 } | |
373 | |
374 void ManagedUserSettingsService::InformSubscribers() { | |
375 if (!IsReady()) | |
376 return; | |
377 | |
378 scoped_ptr<base::DictionaryValue> settings = GetSettings(); | |
379 for (std::vector<SettingsCallback>::iterator it = subscribers_.begin(); | |
380 it != subscribers_.end(); ++it) { | |
381 it->Run(settings.get()); | |
382 } | |
383 } | |
OLD | NEW |