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

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

Issue 7775008: Enable sync for the settings from the Extension Settings API. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Fix mac/win sync tests #2 Created 9 years, 3 months 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.h" 5 #include "chrome/browser/extensions/extension_settings.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/json/json_reader.h" 8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h" 9 #include "base/json/json_writer.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h" 11 #include "base/memory/scoped_ptr.h"
12 #include "content/browser/browser_thread.h"
13 #include "chrome/browser/extensions/extension_settings_leveldb_storage.h" 12 #include "chrome/browser/extensions/extension_settings_leveldb_storage.h"
14 #include "chrome/browser/extensions/extension_settings_noop_storage.h" 13 #include "chrome/browser/extensions/extension_settings_noop_storage.h"
15 #include "chrome/browser/extensions/extension_settings_storage_cache.h" 14 #include "chrome/browser/extensions/extension_settings_storage_cache.h"
15 #include "chrome/browser/extensions/extension_settings_sync_util.h"
16 #include "chrome/common/extensions/extension.h"
17 #include "content/browser/browser_thread.h"
16 #include "third_party/leveldatabase/src/include/leveldb/iterator.h" 18 #include "third_party/leveldatabase/src/include/leveldb/iterator.h"
17 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 19 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
18 20
19 ExtensionSettings::ExtensionSettings(const FilePath& base_path) 21 ExtensionSettings::ExtensionSettings(const FilePath& base_path)
20 : base_path_(base_path) {} 22 : base_path_(base_path),
23 extension_service_(NULL),
24 sync_processor_(NULL) {}
21 25
22 ExtensionSettings::~ExtensionSettings() { 26 ExtensionSettings::~ExtensionSettings() {
23 std::map<std::string, ExtensionSettingsStorage*>::iterator it; 27 std::map<std::string, SyncableExtensionSettingsStorage*>::iterator it;
24 for (it = storage_objs_.begin(); it != storage_objs_.end(); ++it) { 28 for (it = storage_objs_.begin(); it != storage_objs_.end(); ++it) {
25 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, it->second); 29 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, it->second);
26 } 30 }
27 } 31 }
28 32
33 void ExtensionSettings::SetExtensionService(
34 ExtensionServiceInterface* extension_service) {
35 extension_service_ = extension_service;
36 }
37
29 ExtensionSettingsStorage* ExtensionSettings::GetStorage( 38 ExtensionSettingsStorage* ExtensionSettings::GetStorage(
30 const std::string& extension_id) { 39 const std::string& extension_id) const {
31 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 40 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
41 DictionaryValue empty;
42 return GetOrCreateStorageWithSyncData(extension_id, empty);
43 }
32 44
33 std::map<std::string, ExtensionSettingsStorage*>::iterator existing = 45 SyncableExtensionSettingsStorage*
34 storage_objs_.find(extension_id); 46 ExtensionSettings::GetOrCreateStorageWithSyncData(
35 if (existing != storage_objs_.end()) { 47 const std::string& extension_id, const DictionaryValue& sync_data) const {
36 return existing->second; 48 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
49 SyncableExtensionSettingsStorage* storage = GetOrCreateAndInitStorage(
50 ExtensionSettingsStorage::LEVELDB,
51 true,
52 extension_id,
53 sync_data);
54 if (storage == NULL) {
55 // Fall back to an in-memory storage area (cached NOOP).
56 storage = GetOrCreateAndInitStorage(
57 ExtensionSettingsStorage::NOOP,
58 true,
59 extension_id,
60 sync_data);
61 DCHECK(storage != NULL);
37 } 62 }
38 63 return storage;
39 ExtensionSettingsStorage* new_storage =
40 CreateStorage(extension_id, ExtensionSettingsStorage::LEVELDB, true);
41 if (new_storage == NULL) {
42 // Failed to create a leveldb storage for some reason. Use an in memory
43 // storage area (no-op wrapped in a cache) instead.
44 new_storage =
45 CreateStorage(extension_id, ExtensionSettingsStorage::NOOP, true);
46 DCHECK(new_storage != NULL);
47 }
48
49 storage_objs_[extension_id] = new_storage;
50 return new_storage;
51 } 64 }
52 65
53 ExtensionSettingsStorage* ExtensionSettings::GetStorageForTesting( 66 ExtensionSettingsStorage* ExtensionSettings::GetStorageForTesting(
54 ExtensionSettingsStorage::Type type, 67 ExtensionSettingsStorage::Type type,
55 bool cached, 68 bool cached,
56 const std::string& extension_id) { 69 const std::string& extension_id) const {
57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 70 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
71 DictionaryValue empty;
72 ExtensionSettingsStorage* storage =
73 GetOrCreateAndInitStorage(type, cached, extension_id, empty);
74 DCHECK(storage != NULL);
75 return storage;
76 }
58 77
59 std::map<std::string, ExtensionSettingsStorage*>::iterator existing = 78 SyncableExtensionSettingsStorage* ExtensionSettings::GetOrCreateAndInitStorage(
79 ExtensionSettingsStorage::Type type,
80 bool cached,
81 const std::string& extension_id,
82 const DictionaryValue& initial_sync_data) const {
83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
84 std::map<std::string, SyncableExtensionSettingsStorage*>::iterator existing =
60 storage_objs_.find(extension_id); 85 storage_objs_.find(extension_id);
61 if (existing != storage_objs_.end()) { 86 if (existing != storage_objs_.end()) {
62 return existing->second; 87 return existing->second;
63 } 88 }
64 89 return CreateAndInitStorage(type, cached, extension_id, initial_sync_data);
65 ExtensionSettingsStorage* new_storage =
66 CreateStorage(extension_id, type, cached);
67 DCHECK(new_storage != NULL);
68 storage_objs_[extension_id] = new_storage;
69 return new_storage;
70 } 90 }
71 91
72 ExtensionSettingsStorage* ExtensionSettings::CreateStorage( 92 SyncableExtensionSettingsStorage* ExtensionSettings::CreateAndInitStorage(
93 ExtensionSettingsStorage::Type type,
94 bool cached,
73 const std::string& extension_id, 95 const std::string& extension_id,
74 ExtensionSettingsStorage::Type type, 96 const DictionaryValue& initial_sync_data) const {
75 bool cached) {
76 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
98 DCHECK(storage_objs_.count(extension_id) == 0);
77 ExtensionSettingsStorage* storage = NULL; 99 ExtensionSettingsStorage* storage = NULL;
78 switch (type) { 100 switch (type) {
79 case ExtensionSettingsStorage::NOOP: 101 case ExtensionSettingsStorage::NOOP:
80 storage = new ExtensionSettingsNoopStorage(); 102 storage = new ExtensionSettingsNoopStorage();
81 break; 103 break;
82 case ExtensionSettingsStorage::LEVELDB: 104 case ExtensionSettingsStorage::LEVELDB:
83 storage = ExtensionSettingsLeveldbStorage::Create( 105 storage = ExtensionSettingsLeveldbStorage::Create(
84 base_path_, extension_id); 106 base_path_, extension_id);
85 break; 107 break;
86 default: 108 default:
87 NOTREACHED(); 109 NOTREACHED();
88 } 110 }
89 if (storage != NULL && cached) { 111 if (storage == NULL) {
112 return NULL;
113 }
114 if (cached) {
90 storage = new ExtensionSettingsStorageCache(storage); 115 storage = new ExtensionSettingsStorageCache(storage);
91 } 116 }
92 return storage; 117
118 SyncableExtensionSettingsStorage* synced_storage =
119 new SyncableExtensionSettingsStorage(extension_id, storage);
120 if (sync_processor_ != NULL) {
121 synced_storage->StartSyncing(initial_sync_data, sync_processor_);
122 }
123 storage_objs_[extension_id] = synced_storage;
124 return synced_storage;
93 } 125 }
126
127 SyncDataList ExtensionSettings::GetAllSyncData(
128 syncable::ModelType type) const {
129 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
akalin 2011/09/14 05:57:29 ExtensionSettings lives on the FILE thread right?
not at google - send to devlin 2011/09/14 20:23:57 Done.
130 LOG(WARNING) << "Can't synchronously get extension settings unless on " <<
131 "the FILE thread";
132 return SyncDataList();
133 }
134 DCHECK(type == syncable::EXTENSION_SETTINGS);
135 DCHECK(extension_service_ != NULL);
136
137 // For all extensions, get all their settings.
138 // This has the effect of bringing in the entire state of extension settings
139 // in memory; sad.
140 SyncDataList all_sync_data;
141 const ExtensionList* extensions = extension_service_->extensions();
142 for (ExtensionList::const_iterator it = extensions->begin();
143 it != extensions->end(); ++it) {
144 std::string extension_id = (*it)->id();
145 ExtensionSettingsStorage::Result maybe_settings =
146 GetStorage(extension_id)->Get();
147 if (maybe_settings.HasError()) {
148 LOG(WARNING) << "Failed to get settings for " << extension_id << ": " <<
149 maybe_settings.GetError();
150 continue;
151 }
152
153 DictionaryValue* settings = maybe_settings.GetSettings();
154 for (DictionaryValue::key_iterator key_it = settings->begin_keys();
155 key_it != settings->end_keys(); ++key_it) {
156 Value *value;
157 settings->GetWithoutPathExpansion(*key_it, &value);
158 all_sync_data.push_back(
159 extension_settings_sync_util::CreateData(
160 extension_id, *key_it, *value));
161 }
162 }
163
164 return all_sync_data;
165 }
166
167 SyncError ExtensionSettings::MergeDataAndStartSyncing(
168 syncable::ModelType type,
169 const SyncDataList& initial_sync_data,
170 SyncChangeProcessor* sync_processor) {
171 if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
172 MergeDataAndStartSyncing2(type, initial_sync_data, sync_processor);
173 } else {
174 BrowserThread::PostTask(
akalin 2011/09/14 05:57:29 Remove this and DCHECK that you're on FILE thread.
not at google - send to devlin 2011/09/14 20:23:57 Done.
175 BrowserThread::FILE,
176 FROM_HERE,
177 base::Bind(
178 &ExtensionSettings::MergeDataAndStartSyncing2,
179 this,
180 type,
181 initial_sync_data,
182 sync_processor));
183 }
184 return SyncError();
185 }
186
187 void ExtensionSettings::MergeDataAndStartSyncing2(
188 syncable::ModelType type,
189 const SyncDataList& initial_sync_data,
190 SyncChangeProcessor* sync_processor) {
191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
192 DCHECK(type == syncable::EXTENSION_SETTINGS);
193 DCHECK(sync_processor_ == NULL);
194 sync_processor_ = sync_processor;
195
196 // Group the initial sync data by extension id.
197 std::map<std::string, DictionaryValue*> grouped_sync_data;
198 for (SyncDataList::const_iterator it = initial_sync_data.begin();
199 it != initial_sync_data.end(); ++it) {
200 ExtensionSettingSyncData data(*it);
201 if (data.value() == NULL) {
202 LOG(WARNING) << "NULL value in sync data";
203 continue;
204 }
205 DictionaryValue* sync_data = grouped_sync_data[data.extension_id()];
206 if (sync_data == NULL) {
207 sync_data = new DictionaryValue();
208 grouped_sync_data[data.extension_id()] = sync_data;
209 }
210 DCHECK(!sync_data->HasKey(data.key())) <<
211 "Duplicate settings for " << data.extension_id() << "/" << data.key();
212 sync_data->Set(data.key(), data.value()->DeepCopy());
213 }
214
215 // Start syncing all existing storage areas. Any storage areas created in
216 // the future will start being synced as part of the creation process.
217 std::map<std::string, SyncableExtensionSettingsStorage*>::iterator storage_it;
218 for (storage_it = storage_objs_.begin();
219 storage_it != storage_objs_.end(); ++storage_it) {
220 scoped_ptr<DictionaryValue> sync_data(grouped_sync_data[storage_it->first]);
221 if (sync_data.get() == NULL) {
222 DictionaryValue empty;
223 storage_it->second->StartSyncing(empty, sync_processor);
224 } else {
225 storage_it->second->StartSyncing(*sync_data, sync_processor);
226 }
227 grouped_sync_data.erase(storage_it->first);
228 }
229
230 // Eagerly create and init the rest of the storage areas that have sync data.
231 // Under normal circumstances this will probably be all of them.
232 std::map<std::string, DictionaryValue*>::iterator data_it;
233 for (data_it = grouped_sync_data.begin();
234 data_it != grouped_sync_data.end(); ++data_it) {
235 scoped_ptr<DictionaryValue> sync_data(data_it->second);
236 GetOrCreateStorageWithSyncData(data_it->first, *sync_data);
237 }
238 }
239
240 SyncError ExtensionSettings::ProcessSyncChanges(
241 const tracked_objects::Location& from_here,
242 const SyncChangeList& sync_changes) {
243 if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
akalin 2011/09/14 05:57:29 Here, too
not at google - send to devlin 2011/09/14 20:23:57 Done.
244 ProcessSyncChanges2(from_here, sync_changes);
245 } else {
246 BrowserThread::PostTask(
247 BrowserThread::FILE,
248 FROM_HERE,
249 base::Bind(
250 &ExtensionSettings::ProcessSyncChanges2,
251 this,
252 from_here,
253 sync_changes));
254 }
255 return SyncError();
256 }
257
258 void ExtensionSettings::ProcessSyncChanges2(
259 const tracked_objects::Location& from_here,
260 const SyncChangeList& sync_changes) {
261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
262 DCHECK(sync_processor_ != NULL);
263
264 // Group changes by extension, to pass all changes in a single method call.
265 std::map<std::string, ExtensionSettingSyncDataList> grouped_sync_data;
266 for (SyncChangeList::const_iterator it = sync_changes.begin();
267 it != sync_changes.end(); ++it) {
268 ExtensionSettingSyncData data(*it);
269 if (data.value() == NULL) {
270 LOG(WARNING) << "NULL value in sync data";
271 continue;
272 }
273 grouped_sync_data[data.extension_id()].push_back(data);
274 }
275
276 std::map<std::string, ExtensionSettingSyncDataList>::iterator it;
277 DictionaryValue empty;
278 for (it = grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) {
279 GetOrCreateStorageWithSyncData(it->first, empty)->
280 ProcessSyncChanges(it->second);
281 }
282 }
283
284 void ExtensionSettings::StopSyncing(syncable::ModelType type) {
285 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
286 // Re-run ths method on the FILE thread.
akalin 2011/09/14 05:57:29 DCHECK, etc.
not at google - send to devlin 2011/09/14 20:23:57 Done.
287 BrowserThread::PostTask(
288 BrowserThread::FILE,
289 FROM_HERE,
290 base::Bind(
291 &ExtensionSettings::StopSyncing,
292 this,
293 type));
294 return;
295 }
296 DCHECK(type == syncable::EXTENSION_SETTINGS);
297 DCHECK(sync_processor_ != NULL);
298 sync_processor_ = NULL;
299
300 std::map<std::string, SyncableExtensionSettingsStorage*>::iterator it;
301 for (it = storage_objs_.begin(); it != storage_objs_.end(); ++it) {
302 it->second->StopSyncing();
303 }
304 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698