Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(49)

Side by Side Diff: chrome/browser/extensions/extension_settings_backend.cc

Issue 8375047: Separate the syncing of extension settings and app settings into separate data (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "chrome/browser/extensions/extension_settings_backend.h" 5 #include "chrome/browser/extensions/extension_settings_backend.h"
6 6
7 #include "base/compiler_specific.h" 7 #include "base/compiler_specific.h"
8 #include "base/file_util.h" 8 #include "base/file_util.h"
9 #include "base/json/json_reader.h" 9 #include "base/json/json_reader.h"
10 #include "base/json/json_writer.h" 10 #include "base/json/json_writer.h"
(...skipping 20 matching lines...) Expand all
31 // restrictive than that. 31 // restrictive than that.
32 const size_t kQuotaPerSettingBytes = 2048; 32 const size_t kQuotaPerSettingBytes = 2048;
33 33
34 // Max number of settings per extension. Keep low for sync. 34 // Max number of settings per extension. Keep low for sync.
35 const size_t kMaxSettingKeys = 512; 35 const size_t kMaxSettingKeys = 512;
36 36
37 } // namespace 37 } // namespace
38 38
39 ExtensionSettingsBackend::ExtensionSettingsBackend( 39 ExtensionSettingsBackend::ExtensionSettingsBackend(
40 const FilePath& base_path, 40 const FilePath& base_path,
41 const scoped_refptr<ObserverListThreadSafe<ExtensionSettingsObserver> >& 41 const scoped_refptr<ExtensionSettingsObserverList>& observers)
42 observers)
43 : base_path_(base_path), 42 : base_path_(base_path),
44 observers_(observers), 43 observers_(observers),
44 sync_type_(syncable::UNSPECIFIED),
45 sync_processor_(NULL) { 45 sync_processor_(NULL) {
46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 46 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
47 } 47 }
48 48
49 ExtensionSettingsBackend::~ExtensionSettingsBackend() { 49 ExtensionSettingsBackend::~ExtensionSettingsBackend() {
50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
51 } 51 }
52 52
53 ExtensionSettingsStorage* ExtensionSettingsBackend::GetStorage( 53 ExtensionSettingsStorage* ExtensionSettingsBackend::GetStorage(
54 const std::string& extension_id) const { 54 const std::string& extension_id) const {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 kTotalQuotaBytes, kQuotaPerSettingBytes, kMaxSettingKeys, storage); 86 kTotalQuotaBytes, kQuotaPerSettingBytes, kMaxSettingKeys, storage);
87 87
88 syncable_storage = 88 syncable_storage =
89 linked_ptr<SyncableExtensionSettingsStorage>( 89 linked_ptr<SyncableExtensionSettingsStorage>(
90 new SyncableExtensionSettingsStorage( 90 new SyncableExtensionSettingsStorage(
91 observers_, 91 observers_,
92 extension_id, 92 extension_id,
93 storage)); 93 storage));
94 if (sync_processor_) { 94 if (sync_processor_) {
95 // TODO(kalman): do something if StartSyncing fails. 95 // TODO(kalman): do something if StartSyncing fails.
96 ignore_result(syncable_storage->StartSyncing(sync_data, sync_processor_)); 96 ignore_result(syncable_storage->StartSyncing(
97 sync_type_, sync_data, sync_processor_));
97 } 98 }
98 99
99 storage_objs_[extension_id] = syncable_storage; 100 storage_objs_[extension_id] = syncable_storage;
100 return syncable_storage.get(); 101 return syncable_storage.get();
101 } 102 }
102 103
103 void ExtensionSettingsBackend::DeleteExtensionData( 104 void ExtensionSettingsBackend::DeleteStorage(const std::string& extension_id) {
104 const std::string& extension_id) {
105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
106 StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id); 106 StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id);
107 if (maybe_storage == storage_objs_.end()) { 107 if (maybe_storage == storage_objs_.end()) {
108 return; 108 return;
109 } 109 }
110 110
111 // Clear settings when the extension is uninstalled. Leveldb implementations 111 // Clear settings when the extension is uninstalled. Leveldb implementations
112 // will also delete the database from disk when the object is destroyed as 112 // will also delete the database from disk when the object is destroyed as
113 // a result of being removed from |storage_objs_|. 113 // a result of being removed from |storage_objs_|.
114 maybe_storage->second->Clear(); 114 maybe_storage->second->Clear();
115 storage_objs_.erase(maybe_storage); 115 storage_objs_.erase(maybe_storage);
116 } 116 }
117 117
118 void ExtensionSettingsBackend::TriggerOnSettingsChanged( 118 void ExtensionSettingsBackend::TriggerOnSettingsChanged(
119 Profile* profile, 119 Profile* profile,
120 const std::string& extension_id, 120 const std::string& extension_id,
121 const ExtensionSettingChanges& changes) const { 121 const ExtensionSettingChanges& changes) const {
122 observers_->Notify( 122 observers_->Notify(
123 &ExtensionSettingsObserver::OnSettingsChanged, 123 &ExtensionSettingsObserver::OnSettingsChanged,
124 profile, 124 profile,
125 extension_id, 125 extension_id,
126 changes); 126 changes);
127 } 127 }
128 128
129 std::set<std::string> ExtensionSettingsBackend::GetKnownExtensionIDs() const { 129 std::set<std::string> ExtensionSettingsBackend::GetKnownExtensionIDs() const {
130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
131 std::set<std::string> result; 131 std::set<std::string> result;
132 132
133 // TODO(kalman): we will need to do something to disambiguate between app
134 // settings and extension settings, since settings for apps should be synced
135 // iff app sync is turned on, ditto for extensions.
136
137 // Extension IDs live in-memory and/or on disk. The cache will contain all 133 // Extension IDs live in-memory and/or on disk. The cache will contain all
138 // that are in-memory. 134 // that are in-memory.
139 for (StorageObjMap::iterator it = storage_objs_.begin(); 135 for (StorageObjMap::iterator it = storage_objs_.begin();
140 it != storage_objs_.end(); ++it) { 136 it != storage_objs_.end(); ++it) {
141 result.insert(it->first); 137 result.insert(it->first);
142 } 138 }
143 139
144 // Leveldb databases are directories inside base_path_. 140 // Leveldb databases are directories inside base_path_.
145 file_util::FileEnumerator::FindInfo find_info; 141 file_util::FileEnumerator::FindInfo find_info;
146 file_util::FileEnumerator extension_dirs( 142 file_util::FileEnumerator extension_dirs(
147 base_path_, false, file_util::FileEnumerator::DIRECTORIES); 143 base_path_, false, file_util::FileEnumerator::DIRECTORIES);
148 while (!extension_dirs.Next().empty()) { 144 while (!extension_dirs.Next().empty()) {
149 extension_dirs.GetFindInfo(&find_info); 145 extension_dirs.GetFindInfo(&find_info);
150 FilePath extension_dir(file_util::FileEnumerator::GetFilename(find_info)); 146 FilePath extension_dir(file_util::FileEnumerator::GetFilename(find_info));
151 DCHECK(!extension_dir.IsAbsolute()); 147 DCHECK(!extension_dir.IsAbsolute());
152 // Extension IDs are created as std::strings so they *should* be ASCII. 148 // Extension IDs are created as std::strings so they *should* be ASCII.
153 std::string maybe_as_ascii(extension_dir.MaybeAsASCII()); 149 std::string maybe_as_ascii(extension_dir.MaybeAsASCII());
154 if (!maybe_as_ascii.empty()) { 150 if (!maybe_as_ascii.empty()) {
155 result.insert(maybe_as_ascii); 151 result.insert(maybe_as_ascii);
156 } 152 }
157 } 153 }
158 154
159 return result; 155 return result;
160 } 156 }
161 157
162 SyncDataList ExtensionSettingsBackend::GetAllSyncData( 158 SyncDataList ExtensionSettingsBackend::GetAllSyncData(
163 syncable::ModelType type) const { 159 syncable::ModelType type) const {
164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
165 DCHECK_EQ(type, syncable::EXTENSION_SETTINGS); 161 // Ignore the type, it's just for sanity checking; assume that whatever base
162 // path we're constructed with is correct for the sync type.
163 DCHECK(type == syncable::EXTENSION_SETTINGS ||
164 type == syncable::APP_SETTINGS);
166 165
167 // For all extensions, get all their settings. 166 // For all extensions, get all their settings. This has the effect
168 // This has the effect of bringing in the entire state of extension settings 167 // of bringing in the entire state of extension settings in memory; sad.
169 // in memory; sad.
170 SyncDataList all_sync_data; 168 SyncDataList all_sync_data;
171 std::set<std::string> known_extension_ids(GetKnownExtensionIDs()); 169 std::set<std::string> known_extension_ids(GetKnownExtensionIDs());
172 170
173 for (std::set<std::string>::const_iterator it = known_extension_ids.begin(); 171 for (std::set<std::string>::const_iterator it = known_extension_ids.begin();
174 it != known_extension_ids.end(); ++it) { 172 it != known_extension_ids.end(); ++it) {
175 ExtensionSettingsStorage::Result maybe_settings = GetStorage(*it)->Get(); 173 ExtensionSettingsStorage::Result maybe_settings = GetStorage(*it)->Get();
176 if (maybe_settings.HasError()) { 174 if (maybe_settings.HasError()) {
177 LOG(WARNING) << "Failed to get settings for " << *it << ": " << 175 LOG(WARNING) << "Failed to get settings for " << *it << ": " <<
178 maybe_settings.GetError(); 176 maybe_settings.GetError();
179 continue; 177 continue;
(...skipping 10 matching lines...) Expand all
190 } 188 }
191 189
192 return all_sync_data; 190 return all_sync_data;
193 } 191 }
194 192
195 SyncError ExtensionSettingsBackend::MergeDataAndStartSyncing( 193 SyncError ExtensionSettingsBackend::MergeDataAndStartSyncing(
196 syncable::ModelType type, 194 syncable::ModelType type,
197 const SyncDataList& initial_sync_data, 195 const SyncDataList& initial_sync_data,
198 SyncChangeProcessor* sync_processor) { 196 SyncChangeProcessor* sync_processor) {
199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
200 DCHECK_EQ(type, syncable::EXTENSION_SETTINGS); 198 DCHECK(type == syncable::EXTENSION_SETTINGS ||
199 type == syncable::APP_SETTINGS);
200 DCHECK_EQ(sync_type_, syncable::UNSPECIFIED);
201 DCHECK(!sync_processor_); 201 DCHECK(!sync_processor_);
202
203 sync_type_ = type;
202 sync_processor_ = sync_processor; 204 sync_processor_ = sync_processor;
203 205
204 // Group the initial sync data by extension id. 206 // Group the initial sync data by extension id.
205 std::map<std::string, linked_ptr<DictionaryValue> > grouped_sync_data; 207 std::map<std::string, linked_ptr<DictionaryValue> > grouped_sync_data;
206 for (SyncDataList::const_iterator it = initial_sync_data.begin(); 208 for (SyncDataList::const_iterator it = initial_sync_data.begin();
207 it != initial_sync_data.end(); ++it) { 209 it != initial_sync_data.end(); ++it) {
208 ExtensionSettingSyncData data(*it); 210 ExtensionSettingSyncData data(*it);
209 linked_ptr<DictionaryValue> sync_data = 211 linked_ptr<DictionaryValue> sync_data =
210 grouped_sync_data[data.extension_id()]; 212 grouped_sync_data[data.extension_id()];
211 if (!sync_data.get()) { 213 if (!sync_data.get()) {
212 sync_data = linked_ptr<DictionaryValue>(new DictionaryValue()); 214 sync_data = linked_ptr<DictionaryValue>(new DictionaryValue());
213 grouped_sync_data[data.extension_id()] = sync_data; 215 grouped_sync_data[data.extension_id()] = sync_data;
214 } 216 }
215 DCHECK(!sync_data->HasKey(data.key())) << 217 DCHECK(!sync_data->HasKey(data.key())) <<
216 "Duplicate settings for " << data.extension_id() << "/" << data.key(); 218 "Duplicate settings for " << data.extension_id() << "/" << data.key();
217 sync_data->Set(data.key(), data.value().DeepCopy()); 219 sync_data->Set(data.key(), data.value().DeepCopy());
218 } 220 }
219 221
220 // Start syncing all existing storage areas. Any storage areas created in 222 // Start syncing all existing storage areas. Any storage areas created in
221 // the future will start being synced as part of the creation process. 223 // the future will start being synced as part of the creation process.
222 for (StorageObjMap::iterator it = storage_objs_.begin(); 224 for (StorageObjMap::iterator it = storage_objs_.begin();
223 it != storage_objs_.end(); ++it) { 225 it != storage_objs_.end(); ++it) {
224 std::map<std::string, linked_ptr<DictionaryValue> >::iterator 226 std::map<std::string, linked_ptr<DictionaryValue> >::iterator
225 maybe_sync_data = grouped_sync_data.find(it->first); 227 maybe_sync_data = grouped_sync_data.find(it->first);
226 if (maybe_sync_data != grouped_sync_data.end()) { 228 if (maybe_sync_data != grouped_sync_data.end()) {
227 // TODO(kalman): do something if StartSyncing fails. 229 // TODO(kalman): do something if StartSyncing fails.
228 ignore_result( 230 ignore_result(
229 it->second->StartSyncing(*maybe_sync_data->second, sync_processor)); 231 it->second->StartSyncing(
232 type, *maybe_sync_data->second, sync_processor));
230 grouped_sync_data.erase(it->first); 233 grouped_sync_data.erase(it->first);
231 } else { 234 } else {
232 DictionaryValue empty; 235 DictionaryValue empty;
233 // TODO(kalman): do something if StartSyncing fails. 236 // TODO(kalman): do something if StartSyncing fails.
234 ignore_result(it->second->StartSyncing(empty, sync_processor)); 237 ignore_result(it->second->StartSyncing(type, empty, sync_processor));
235 } 238 }
236 } 239 }
237 240
238 // Eagerly create and init the rest of the storage areas that have sync data. 241 // Eagerly create and init the rest of the storage areas that have sync data.
239 // Under normal circumstances (i.e. not first-time sync) this will be all of 242 // Under normal circumstances (i.e. not first-time sync) this will be all of
240 // them. 243 // them.
241 for (std::map<std::string, linked_ptr<DictionaryValue> >::iterator it = 244 for (std::map<std::string, linked_ptr<DictionaryValue> >::iterator it =
242 grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) { 245 grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) {
243 GetOrCreateStorageWithSyncData(it->first, *it->second); 246 GetOrCreateStorageWithSyncData(it->first, *it->second);
244 } 247 }
245 248
246 return SyncError(); 249 return SyncError();
247 } 250 }
248 251
249 SyncError ExtensionSettingsBackend::ProcessSyncChanges( 252 SyncError ExtensionSettingsBackend::ProcessSyncChanges(
250 const tracked_objects::Location& from_here, 253 const tracked_objects::Location& from_here,
251 const SyncChangeList& sync_changes) { 254 const SyncChangeList& sync_changes) {
252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
253 DCHECK(sync_processor_); 256 DCHECK(sync_processor_);
254 257
255 // Group changes by extension, to pass all changes in a single method call. 258 // Group changes by extension, to pass all changes in a single method call.
256 std::map<std::string, ExtensionSettingSyncDataList> grouped_sync_data; 259 std::map<std::string, ExtensionSettingSyncDataList> grouped_sync_data;
257 for (SyncChangeList::const_iterator it = sync_changes.begin(); 260 for (SyncChangeList::const_iterator it = sync_changes.begin();
258 it != sync_changes.end(); ++it) { 261 it != sync_changes.end(); ++it) {
259 ExtensionSettingSyncData data(*it); 262 ExtensionSettingSyncData data(*it);
260 grouped_sync_data[data.extension_id()].push_back(data); 263 grouped_sync_data[data.extension_id()].push_back(data);
261 } 264 }
262 265
266 // Create any storage areas that don't exist yet but have sync data.
263 DictionaryValue empty; 267 DictionaryValue empty;
264 for (std::map<std::string, ExtensionSettingSyncDataList>::iterator 268 for (std::map<std::string, ExtensionSettingSyncDataList>::iterator
265 it = grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) { 269 it = grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) {
266 // TODO(kalman): do something if ProcessSyncChanges fails. 270 // TODO(kalman): do something if ProcessSyncChanges fails.
267 ignore_result( 271 ignore_result(
268 GetOrCreateStorageWithSyncData(it->first, empty)-> 272 GetOrCreateStorageWithSyncData(it->first, empty)->
269 ProcessSyncChanges(it->second)); 273 ProcessSyncChanges(it->second));
270 } 274 }
271 275
272 return SyncError(); 276 return SyncError();
273 } 277 }
274 278
275 void ExtensionSettingsBackend::StopSyncing(syncable::ModelType type) { 279 void ExtensionSettingsBackend::StopSyncing(syncable::ModelType type) {
276 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 280 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
281 DCHECK(type == syncable::EXTENSION_SETTINGS ||
282 type == syncable::APP_SETTINGS);
283 DCHECK_EQ(type, sync_type_);
277 DCHECK(sync_processor_); 284 DCHECK(sync_processor_);
285
286 sync_type_ = syncable::UNSPECIFIED;
278 sync_processor_ = NULL; 287 sync_processor_ = NULL;
279 288
280 for (StorageObjMap::iterator it = storage_objs_.begin(); 289 for (StorageObjMap::iterator it = storage_objs_.begin();
281 it != storage_objs_.end(); ++it) { 290 it != storage_objs_.end(); ++it) {
282 it->second->StopSyncing(); 291 it->second->StopSyncing();
283 } 292 }
284 } 293 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698