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

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: Review #2 against correct branch 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"
8 #include "base/json/json_reader.h" 7 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h" 8 #include "base/json/json_writer.h"
10 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/linked_ptr.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 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
24 for (it = storage_objs_.begin(); it != storage_objs_.end(); ++it) { 28 }
25 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, it->second); 29
26 } 30 void ExtensionSettings::SetExtensionService(
31 ExtensionServiceInterface* extension_service) {
32 extension_service_ = extension_service;
27 } 33 }
28 34
29 ExtensionSettingsStorage* ExtensionSettings::GetStorage( 35 ExtensionSettingsStorage* ExtensionSettings::GetStorage(
30 const std::string& extension_id) { 36 const std::string& extension_id) const {
31 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 37 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
38 DictionaryValue empty;
39 return GetOrCreateStorageWithSyncData(extension_id, empty);
40 }
32 41
33 std::map<std::string, ExtensionSettingsStorage*>::iterator existing = 42 SyncableExtensionSettingsStorage*
34 storage_objs_.find(extension_id); 43 ExtensionSettings::GetOrCreateStorageWithSyncData(
35 if (existing != storage_objs_.end()) { 44 const std::string& extension_id, const DictionaryValue& sync_data) const {
36 return existing->second; 45 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
46 SyncableExtensionSettingsStorage* storage = GetOrCreateAndInitStorage(
47 ExtensionSettingsStorage::LEVELDB,
48 true,
49 extension_id,
50 sync_data);
51 if (!storage) {
52 // Fall back to an in-memory storage area (cached NOOP).
53 storage = GetOrCreateAndInitStorage(
54 ExtensionSettingsStorage::NOOP,
55 true,
56 extension_id,
57 sync_data);
58 DCHECK(storage);
37 } 59 }
38 60 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 } 61 }
52 62
53 ExtensionSettingsStorage* ExtensionSettings::GetStorageForTesting( 63 ExtensionSettingsStorage* ExtensionSettings::GetStorageForTesting(
54 ExtensionSettingsStorage::Type type, 64 ExtensionSettingsStorage::Type type,
55 bool cached, 65 bool cached,
56 const std::string& extension_id) { 66 const std::string& extension_id) const {
57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 67 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
58 68 DictionaryValue empty;
59 std::map<std::string, ExtensionSettingsStorage*>::iterator existing = 69 ExtensionSettingsStorage* storage =
60 storage_objs_.find(extension_id); 70 GetOrCreateAndInitStorage(type, cached, extension_id, empty);
61 if (existing != storage_objs_.end()) { 71 DCHECK(storage);
62 return existing->second; 72 return storage;
63 }
64
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 } 73 }
71 74
72 ExtensionSettingsStorage* ExtensionSettings::CreateStorage( 75 SyncableExtensionSettingsStorage* ExtensionSettings::GetOrCreateAndInitStorage(
76 ExtensionSettingsStorage::Type type,
77 bool cached,
73 const std::string& extension_id, 78 const std::string& extension_id,
79 const DictionaryValue& initial_sync_data) const {
80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
81 StorageObjMap::iterator existing = storage_objs_.find(extension_id);
82 if (existing != storage_objs_.end()) {
83 return existing->second.get();
84 }
85 return CreateAndInitStorage(type, cached, extension_id, initial_sync_data);
86 }
87
88 SyncableExtensionSettingsStorage* ExtensionSettings::CreateAndInitStorage(
74 ExtensionSettingsStorage::Type type, 89 ExtensionSettingsStorage::Type type,
75 bool cached) { 90 bool cached,
91 const std::string& extension_id,
92 const DictionaryValue& initial_sync_data) const {
76 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
94 DCHECK_EQ(0u, storage_objs_.count(extension_id));
77 ExtensionSettingsStorage* storage = NULL; 95 ExtensionSettingsStorage* storage = NULL;
78 switch (type) { 96 switch (type) {
79 case ExtensionSettingsStorage::NOOP: 97 case ExtensionSettingsStorage::NOOP:
80 storage = new ExtensionSettingsNoopStorage(); 98 storage = new ExtensionSettingsNoopStorage();
81 break; 99 break;
82 case ExtensionSettingsStorage::LEVELDB: 100 case ExtensionSettingsStorage::LEVELDB:
83 storage = ExtensionSettingsLeveldbStorage::Create( 101 storage = ExtensionSettingsLeveldbStorage::Create(
84 base_path_, extension_id); 102 base_path_, extension_id);
85 break; 103 break;
86 default: 104 default:
87 NOTREACHED(); 105 NOTREACHED();
88 } 106 }
89 if (storage != NULL && cached) { 107 if (!storage) {
108 return NULL;
109 }
110 if (cached) {
90 storage = new ExtensionSettingsStorageCache(storage); 111 storage = new ExtensionSettingsStorageCache(storage);
91 } 112 }
92 return storage; 113
114 SyncableExtensionSettingsStorage* synced_storage =
115 new SyncableExtensionSettingsStorage(extension_id, storage);
116 if (sync_processor_) {
117 synced_storage->StartSyncing(initial_sync_data, sync_processor_);
118 }
119 storage_objs_[extension_id] =
120 linked_ptr<SyncableExtensionSettingsStorage>(synced_storage);
121 return synced_storage;
93 } 122 }
123
124 SyncDataList ExtensionSettings::GetAllSyncData(
125 syncable::ModelType type) const {
126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
127 DCHECK_EQ(type, syncable::EXTENSION_SETTINGS);
128
129 // For all extensions, get all their settings.
130 // This has the effect of bringing in the entire state of extension settings
131 // in memory; sad.
132 SyncDataList all_sync_data;
133 std::vector<std::string> extension_ids(
akalin 2011/09/17 08:44:47 Wait, this will include apps, too, right? Surely
not at google - send to devlin 2011/09/19 07:10:47 Apps are fine, no reason to filter them out? Anyw
akalin 2011/09/19 07:49:16 Well, you can turn extension sync and app sync on
not at google - send to devlin 2011/09/19 08:42:19 Ah right, that's what you meant. Interesting. Th
134 extension_service_->GetAllExtensionIds());
akalin 2011/09/17 08:44:47 hmm, problem. I'm pretty sure ExtensionService li
not at google - send to devlin 2011/09/19 07:10:47 Yeah, this cleans up a whole lot of stuff. See co
135
136 for (std::vector<std::string>::iterator it = extension_ids.begin();
akalin 2011/09/17 08:44:47 const_iterator
not at google - send to devlin 2011/09/19 07:10:47 Done.
137 it != extension_ids.end(); ++it) {
138 ExtensionSettingsStorage::Result maybe_settings = GetStorage(*it)->Get();
139 if (maybe_settings.HasError()) {
140 LOG(WARNING) << "Failed to get settings for " << *it << ": " <<
141 maybe_settings.GetError();
142 continue;
143 }
144
145 DictionaryValue* settings = maybe_settings.GetSettings();
146 for (DictionaryValue::key_iterator key_it = settings->begin_keys();
147 key_it != settings->end_keys(); ++key_it) {
148 Value *value = NULL;
149 settings->GetWithoutPathExpansion(*key_it, &value);
150 all_sync_data.push_back(
151 extension_settings_sync_util::CreateData(*it, *key_it, *value));
152 }
153 }
154
155 return all_sync_data;
156 }
157
158 SyncError ExtensionSettings::MergeDataAndStartSyncing(
159 syncable::ModelType type,
160 const SyncDataList& initial_sync_data,
161 SyncChangeProcessor* sync_processor) {
162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
163 DCHECK_EQ(type, syncable::EXTENSION_SETTINGS);
164 DCHECK(!sync_processor_);
165 sync_processor_ = sync_processor;
166
167 // Group the initial sync data by extension id.
168 std::map<std::string, linked_ptr<DictionaryValue> > grouped_sync_data;
169 for (SyncDataList::const_iterator it = initial_sync_data.begin();
170 it != initial_sync_data.end(); ++it) {
171 ExtensionSettingSyncData data(*it);
172 linked_ptr<DictionaryValue> sync_data =
akalin 2011/09/17 08:44:47 Didn't address my previous comment: prefer using
not at google - send to devlin 2011/09/19 07:10:47 Why here? Unlike below where you can avoid unnece
akalin 2011/09/19 19:24:11 You're right, I think this is fine.
173 grouped_sync_data[data.extension_id()];
174 if (!sync_data.get()) {
175 sync_data = linked_ptr<DictionaryValue>(new DictionaryValue());
176 grouped_sync_data[data.extension_id()] = sync_data;
177 }
178 DCHECK(!sync_data->HasKey(data.key())) <<
179 "Duplicate settings for " << data.extension_id() << "/" << data.key();
180 sync_data->Set(data.key(), data.value().DeepCopy());
181 }
182
183 // Start syncing all existing storage areas. Any storage areas created in
184 // the future will start being synced as part of the creation process.
185 for (StorageObjMap::iterator it = storage_objs_.begin();
186 it != storage_objs_.end(); ++it) {
187 linked_ptr<DictionaryValue> sync_data = grouped_sync_data[it->first];
akalin 2011/09/17 08:44:47 use find() here, too
not at google - send to devlin 2011/09/19 07:10:47 Done.
188 if (sync_data.get()) {
189 it->second->StartSyncing(*sync_data, sync_processor);
190 } else {
191 DictionaryValue empty;
192 it->second->StartSyncing(empty, sync_processor);
193 }
194 grouped_sync_data.erase(it->first);
195 }
196
197 // Eagerly create and init the rest of the storage areas that have sync data.
198 // Under normal circumstances (i.e. not first-time sync) this will be all of
199 // them.
200 for (std::map<std::string, linked_ptr<DictionaryValue> >::iterator it =
201 grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) {
202 GetOrCreateStorageWithSyncData(it->first, *it->second);
203 }
204
205 return SyncError();
206 }
207
208 SyncError ExtensionSettings::ProcessSyncChanges(
209 const tracked_objects::Location& from_here,
210 const SyncChangeList& sync_changes) {
211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
212 DCHECK(sync_processor_);
213
214 // Group changes by extension, to pass all changes in a single method call.
215 std::map<std::string, ExtensionSettingSyncDataList> grouped_sync_data;
216 for (SyncChangeList::const_iterator it = sync_changes.begin();
217 it != sync_changes.end(); ++it) {
218 ExtensionSettingSyncData data(*it);
219 grouped_sync_data[data.extension_id()].push_back(data);
220 }
221
222 DictionaryValue empty;
223 for (std::map<std::string, ExtensionSettingSyncDataList>::iterator
224 it = grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) {
225 GetOrCreateStorageWithSyncData(it->first, empty)->
226 ProcessSyncChanges(it->second);
227 }
228
229 return SyncError();
230 }
231
232 void ExtensionSettings::StopSyncing(syncable::ModelType type) {
233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
234 DCHECK(sync_processor_);
235 sync_processor_ = NULL;
236
237 for (StorageObjMap::iterator it = storage_objs_.begin();
238 it != storage_objs_.end(); ++it) {
239 it->second->StopSyncing();
240 }
241 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698