Add ENABLE_MEDIA_ROUTER define to builds other than Android and iOS.
[chromium-blink-merge.git] / chrome / browser / extensions / api / storage / sync_storage_backend.cc
blobeb4effa2e5574932123609b1b3ccfd272ad89e35
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/extensions/api/storage/sync_storage_backend.h"
7 #include "base/files/file_enumerator.h"
8 #include "base/logging.h"
9 #include "chrome/browser/extensions/api/storage/settings_sync_processor.h"
10 #include "chrome/browser/extensions/api/storage/settings_sync_util.h"
11 #include "chrome/browser/extensions/api/storage/syncable_settings_storage.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "sync/api/sync_error_factory.h"
15 using content::BrowserThread;
17 namespace extensions {
19 namespace {
21 void AddAllSyncData(const std::string& extension_id,
22 const base::DictionaryValue& src,
23 syncer::ModelType type,
24 syncer::SyncDataList* dst) {
25 for (base::DictionaryValue::Iterator it(src); !it.IsAtEnd(); it.Advance()) {
26 dst->push_back(settings_sync_util::CreateData(
27 extension_id, it.key(), it.value(), type));
31 } // namespace
33 SyncStorageBackend::SyncStorageBackend(
34 const scoped_refptr<SettingsStorageFactory>& storage_factory,
35 const base::FilePath& base_path,
36 const SettingsStorageQuotaEnforcer::Limits& quota,
37 const scoped_refptr<SettingsObserverList>& observers,
38 syncer::ModelType sync_type,
39 const syncer::SyncableService::StartSyncFlare& flare)
40 : storage_factory_(storage_factory),
41 base_path_(base_path),
42 quota_(quota),
43 observers_(observers),
44 sync_type_(sync_type),
45 flare_(flare) {
46 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
47 DCHECK(sync_type_ == syncer::EXTENSION_SETTINGS ||
48 sync_type_ == syncer::APP_SETTINGS);
51 SyncStorageBackend::~SyncStorageBackend() {}
53 ValueStore* SyncStorageBackend::GetStorage(const std::string& extension_id) {
54 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
55 base::DictionaryValue empty;
56 return GetOrCreateStorageWithSyncData(extension_id, empty);
59 SyncableSettingsStorage* SyncStorageBackend::GetOrCreateStorageWithSyncData(
60 const std::string& extension_id,
61 const base::DictionaryValue& sync_data) const {
62 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
64 StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id);
65 if (maybe_storage != storage_objs_.end()) {
66 return maybe_storage->second.get();
69 scoped_ptr<SettingsStorageQuotaEnforcer> storage(
70 new SettingsStorageQuotaEnforcer(
71 quota_, storage_factory_->Create(base_path_, extension_id)));
73 // It's fine to create the quota enforcer underneath the sync layer, since
74 // sync will only go ahead if each underlying storage operation succeeds.
75 linked_ptr<SyncableSettingsStorage> syncable_storage(
76 new SyncableSettingsStorage(
77 observers_, extension_id, storage.release(), sync_type_, flare_));
78 storage_objs_[extension_id] = syncable_storage;
80 if (sync_processor_.get()) {
81 syncer::SyncError error = syncable_storage->StartSyncing(
82 sync_data, CreateSettingsSyncProcessor(extension_id).Pass());
83 if (error.IsSet())
84 syncable_storage.get()->StopSyncing();
86 return syncable_storage.get();
89 void SyncStorageBackend::DeleteStorage(const std::string& extension_id) {
90 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
92 // Clear settings when the extension is uninstalled. Leveldb implementations
93 // will also delete the database from disk when the object is destroyed as a
94 // result of being removed from |storage_objs_|.
96 // TODO(kalman): always GetStorage here (rather than only clearing if it
97 // exists) since the storage area may have been unloaded, but we still want
98 // to clear the data from disk.
99 // However, this triggers http://crbug.com/111072.
100 StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id);
101 if (maybe_storage == storage_objs_.end())
102 return;
103 maybe_storage->second->Clear();
104 storage_objs_.erase(extension_id);
107 std::set<std::string> SyncStorageBackend::GetKnownExtensionIDs() const {
108 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
109 std::set<std::string> result;
111 // Storage areas can be in-memory as well as on disk. |storage_objs_| will
112 // contain all that are in-memory.
113 for (StorageObjMap::iterator it = storage_objs_.begin();
114 it != storage_objs_.end();
115 ++it) {
116 result.insert(it->first);
119 // Leveldb databases are directories inside |base_path_|.
120 base::FileEnumerator extension_dirs(
121 base_path_, false, base::FileEnumerator::DIRECTORIES);
122 while (!extension_dirs.Next().empty()) {
123 base::FilePath extension_dir = extension_dirs.GetInfo().GetName();
124 DCHECK(!extension_dir.IsAbsolute());
125 // Extension IDs are created as std::strings so they *should* be ASCII.
126 std::string maybe_as_ascii(extension_dir.MaybeAsASCII());
127 if (!maybe_as_ascii.empty()) {
128 result.insert(maybe_as_ascii);
132 return result;
135 syncer::SyncDataList SyncStorageBackend::GetAllSyncData(syncer::ModelType type)
136 const {
137 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
138 // Ignore the type, it's just for sanity checking; assume that whatever base
139 // path we're constructed with is correct for the sync type.
140 DCHECK(type == syncer::EXTENSION_SETTINGS || type == syncer::APP_SETTINGS);
142 // For all extensions, get all their settings. This has the effect
143 // of bringing in the entire state of extension settings in memory; sad.
144 syncer::SyncDataList all_sync_data;
145 std::set<std::string> known_extension_ids(GetKnownExtensionIDs());
147 for (std::set<std::string>::const_iterator it = known_extension_ids.begin();
148 it != known_extension_ids.end();
149 ++it) {
150 ValueStore::ReadResult maybe_settings =
151 GetOrCreateStorageWithSyncData(*it, base::DictionaryValue())->Get();
152 if (maybe_settings->HasError()) {
153 LOG(WARNING) << "Failed to get settings for " << *it << ": "
154 << maybe_settings->error().message;
155 continue;
157 AddAllSyncData(*it, maybe_settings->settings(), type, &all_sync_data);
160 return all_sync_data;
163 syncer::SyncMergeResult SyncStorageBackend::MergeDataAndStartSyncing(
164 syncer::ModelType type,
165 const syncer::SyncDataList& initial_sync_data,
166 scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
167 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
168 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
169 DCHECK_EQ(sync_type_, type);
170 DCHECK(!sync_processor_.get());
171 DCHECK(sync_processor.get());
172 DCHECK(sync_error_factory.get());
174 sync_processor_ = sync_processor.Pass();
175 sync_error_factory_ = sync_error_factory.Pass();
177 // Group the initial sync data by extension id.
178 std::map<std::string, linked_ptr<base::DictionaryValue> > grouped_sync_data;
179 for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin();
180 it != initial_sync_data.end();
181 ++it) {
182 SettingSyncData data(*it);
183 linked_ptr<base::DictionaryValue> sync_data =
184 grouped_sync_data[data.extension_id()];
185 if (!sync_data.get()) {
186 sync_data =
187 linked_ptr<base::DictionaryValue>(new base::DictionaryValue());
188 grouped_sync_data[data.extension_id()] = sync_data;
190 DCHECK(!sync_data->HasKey(data.key())) << "Duplicate settings for "
191 << data.extension_id() << "/"
192 << data.key();
193 sync_data->SetWithoutPathExpansion(data.key(), data.value().DeepCopy());
196 // Start syncing all existing storage areas. Any storage areas created in
197 // the future will start being synced as part of the creation process.
198 for (StorageObjMap::iterator it = storage_objs_.begin();
199 it != storage_objs_.end();
200 ++it) {
201 std::map<std::string, linked_ptr<base::DictionaryValue> >::iterator
202 maybe_sync_data = grouped_sync_data.find(it->first);
203 syncer::SyncError error;
204 if (maybe_sync_data != grouped_sync_data.end()) {
205 error = it->second->StartSyncing(
206 *maybe_sync_data->second,
207 CreateSettingsSyncProcessor(it->first).Pass());
208 grouped_sync_data.erase(it->first);
209 } else {
210 base::DictionaryValue empty;
211 error = it->second->StartSyncing(
212 empty, CreateSettingsSyncProcessor(it->first).Pass());
214 if (error.IsSet())
215 it->second->StopSyncing();
218 // Eagerly create and init the rest of the storage areas that have sync data.
219 // Under normal circumstances (i.e. not first-time sync) this will be all of
220 // them.
221 for (std::map<std::string, linked_ptr<base::DictionaryValue> >::iterator it =
222 grouped_sync_data.begin();
223 it != grouped_sync_data.end();
224 ++it) {
225 GetOrCreateStorageWithSyncData(it->first, *it->second);
228 return syncer::SyncMergeResult(type);
231 syncer::SyncError SyncStorageBackend::ProcessSyncChanges(
232 const tracked_objects::Location& from_here,
233 const syncer::SyncChangeList& sync_changes) {
234 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
235 DCHECK(sync_processor_.get());
237 // Group changes by extension, to pass all changes in a single method call.
238 std::map<std::string, SettingSyncDataList> grouped_sync_data;
239 for (syncer::SyncChangeList::const_iterator it = sync_changes.begin();
240 it != sync_changes.end();
241 ++it) {
242 SettingSyncData data(*it);
243 grouped_sync_data[data.extension_id()].push_back(data);
246 // Create any storage areas that don't exist yet but have sync data.
247 base::DictionaryValue empty;
248 for (std::map<std::string, SettingSyncDataList>::iterator it =
249 grouped_sync_data.begin();
250 it != grouped_sync_data.end();
251 ++it) {
252 SyncableSettingsStorage* storage =
253 GetOrCreateStorageWithSyncData(it->first, empty);
254 syncer::SyncError error = storage->ProcessSyncChanges(it->second);
255 if (error.IsSet())
256 storage->StopSyncing();
259 return syncer::SyncError();
262 void SyncStorageBackend::StopSyncing(syncer::ModelType type) {
263 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
264 DCHECK(type == syncer::EXTENSION_SETTINGS || type == syncer::APP_SETTINGS);
265 DCHECK_EQ(sync_type_, type);
267 for (StorageObjMap::iterator it = storage_objs_.begin();
268 it != storage_objs_.end();
269 ++it) {
270 // Some storage areas may have already stopped syncing if they had areas
271 // and syncing was disabled, but StopSyncing is safe to call multiple times.
272 it->second->StopSyncing();
275 sync_processor_.reset();
276 sync_error_factory_.reset();
279 scoped_ptr<SettingsSyncProcessor>
280 SyncStorageBackend::CreateSettingsSyncProcessor(const std::string& extension_id)
281 const {
282 CHECK(sync_processor_.get());
283 return scoped_ptr<SettingsSyncProcessor>(new SettingsSyncProcessor(
284 extension_id, sync_type_, sync_processor_.get()));
287 } // namespace extensions