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

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 #3 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/file_util.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/linked_ptr.h"
11 #include "base/memory/scoped_ptr.h" 12 #include "base/memory/scoped_ptr.h"
12 #include "content/browser/browser_thread.h"
13 #include "chrome/browser/extensions/extension_settings_leveldb_storage.h" 13 #include "chrome/browser/extensions/extension_settings_leveldb_storage.h"
14 #include "chrome/browser/extensions/extension_settings_noop_storage.h" 14 #include "chrome/browser/extensions/extension_settings_noop_storage.h"
15 #include "chrome/browser/extensions/extension_settings_storage_cache.h" 15 #include "chrome/browser/extensions/extension_settings_storage_cache.h"
16 #include "chrome/browser/extensions/extension_settings_sync_util.h"
17 #include "chrome/common/extensions/extension.h"
18 #include "content/browser/browser_thread.h"
16 #include "third_party/leveldatabase/src/include/leveldb/iterator.h" 19 #include "third_party/leveldatabase/src/include/leveldb/iterator.h"
17 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" 20 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
18 21
19 ExtensionSettings::ExtensionSettings(const FilePath& base_path) 22 ExtensionSettings::ExtensionSettings(const FilePath& base_path)
20 : base_path_(base_path) {} 23 : base_path_(base_path),
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) {
25 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, it->second);
26 }
27 } 28 }
28 29
29 ExtensionSettingsStorage* ExtensionSettings::GetStorage( 30 ExtensionSettingsStorage* ExtensionSettings::GetStorage(
30 const std::string& extension_id) { 31 const std::string& extension_id) const {
31 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 32 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
33 DictionaryValue empty;
34 return GetOrCreateStorageWithSyncData(extension_id, empty);
35 }
32 36
33 std::map<std::string, ExtensionSettingsStorage*>::iterator existing = 37 SyncableExtensionSettingsStorage*
34 storage_objs_.find(extension_id); 38 ExtensionSettings::GetOrCreateStorageWithSyncData(
35 if (existing != storage_objs_.end()) { 39 const std::string& extension_id, const DictionaryValue& sync_data) const {
36 return existing->second; 40 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
41 SyncableExtensionSettingsStorage* storage = GetOrCreateAndInitStorage(
42 ExtensionSettingsStorage::LEVELDB,
43 true,
44 extension_id,
45 sync_data);
46 if (!storage) {
47 // Fall back to an in-memory storage area (cached NOOP).
akalin 2011/09/19 19:24:11 add comment about how settings in that storage are
not at google - send to devlin 2011/09/20 07:59:36 Hmm so did I. Done.
48 storage = GetOrCreateAndInitStorage(
49 ExtensionSettingsStorage::NOOP,
50 true,
51 extension_id,
52 sync_data);
53 DCHECK(storage);
37 } 54 }
38 55 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 } 56 }
52 57
53 ExtensionSettingsStorage* ExtensionSettings::GetStorageForTesting( 58 ExtensionSettingsStorage* ExtensionSettings::GetStorageForTesting(
54 ExtensionSettingsStorage::Type type, 59 ExtensionSettingsStorage::Type type,
55 bool cached, 60 bool cached,
56 const std::string& extension_id) { 61 const std::string& extension_id) const {
57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 62 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
58 63 DictionaryValue empty;
59 std::map<std::string, ExtensionSettingsStorage*>::iterator existing = 64 ExtensionSettingsStorage* storage =
60 storage_objs_.find(extension_id); 65 GetOrCreateAndInitStorage(type, cached, extension_id, empty);
61 if (existing != storage_objs_.end()) { 66 DCHECK(storage);
62 return existing->second; 67 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 } 68 }
71 69
72 ExtensionSettingsStorage* ExtensionSettings::CreateStorage( 70 SyncableExtensionSettingsStorage* ExtensionSettings::GetOrCreateAndInitStorage(
71 ExtensionSettingsStorage::Type type,
72 bool cached,
73 const std::string& extension_id, 73 const std::string& extension_id,
74 const DictionaryValue& initial_sync_data) const {
75 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
76 StorageObjMap::iterator existing = storage_objs_.find(extension_id);
77 if (existing != storage_objs_.end()) {
78 return existing->second.get();
79 }
80 return CreateAndInitStorage(type, cached, extension_id, initial_sync_data);
81 }
82
83 SyncableExtensionSettingsStorage* ExtensionSettings::CreateAndInitStorage(
74 ExtensionSettingsStorage::Type type, 84 ExtensionSettingsStorage::Type type,
75 bool cached) { 85 bool cached,
86 const std::string& extension_id,
87 const DictionaryValue& initial_sync_data) const {
76 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 88 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
89 DCHECK_EQ(0u, storage_objs_.count(extension_id));
77 ExtensionSettingsStorage* storage = NULL; 90 ExtensionSettingsStorage* storage = NULL;
78 switch (type) { 91 switch (type) {
79 case ExtensionSettingsStorage::NOOP: 92 case ExtensionSettingsStorage::NOOP:
80 storage = new ExtensionSettingsNoopStorage(); 93 storage = new ExtensionSettingsNoopStorage();
81 break; 94 break;
82 case ExtensionSettingsStorage::LEVELDB: 95 case ExtensionSettingsStorage::LEVELDB:
83 storage = ExtensionSettingsLeveldbStorage::Create( 96 storage = ExtensionSettingsLeveldbStorage::Create(
84 base_path_, extension_id); 97 base_path_, extension_id);
85 break; 98 break;
86 default: 99 default:
87 NOTREACHED(); 100 NOTREACHED();
88 } 101 }
89 if (storage != NULL && cached) { 102 if (!storage) {
103 return NULL;
104 }
105 if (cached) {
90 storage = new ExtensionSettingsStorageCache(storage); 106 storage = new ExtensionSettingsStorageCache(storage);
91 } 107 }
92 return storage; 108
109 SyncableExtensionSettingsStorage* synced_storage =
110 new SyncableExtensionSettingsStorage(extension_id, storage);
111 if (sync_processor_) {
112 synced_storage->StartSyncing(initial_sync_data, sync_processor_);
akalin 2011/09/19 19:24:11 do ignore_result(...StartSyncing()); (#include bas
not at google - send to devlin 2011/09/20 07:59:36 Done.
113 }
114 storage_objs_[extension_id] =
115 linked_ptr<SyncableExtensionSettingsStorage>(synced_storage);
116 return synced_storage;
93 } 117 }
118
119 void ExtensionSettings::GetKnownExtensionIDs(
akalin 2011/09/19 19:24:11 just have this return a set directly also, DCHECK
not at google - send to devlin 2011/09/20 07:59:36 Done.
120 std::set<std::string>* dst) const {
121 // Extension IDs live in-memory and/or on disk.
122 for (StorageObjMap::iterator it = storage_objs_.begin();
123 it != storage_objs_.end(); ++it) {
124 dst->insert(it->first);
125 }
126
127 // Leveldb databases are directories inside base_path_.
128 file_util::FileEnumerator::FindInfo find_info;
129 file_util::FileEnumerator extension_dirs(
130 base_path_, false, file_util::FileEnumerator::DIRECTORIES);
131 while (!extension_dirs.Next().empty()) {
132 extension_dirs.GetFindInfo(&find_info);
133 FilePath extension_dir(file_util::FileEnumerator::GetFilename(find_info));
134 DCHECK(!extension_dir.IsAbsolute());
135 // Extension IDs are created as std::strings so they *should* be ASCII.
136 std::string maybe_as_ascii(extension_dir.MaybeAsASCII());
137 if (!maybe_as_ascii.empty()) {
138 dst->insert(maybe_as_ascii);
139 }
140 }
141 }
142
143 SyncDataList ExtensionSettings::GetAllSyncData(
144 syncable::ModelType type) const {
145 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
146 DCHECK_EQ(type, syncable::EXTENSION_SETTINGS);
147
148 // For all extensions, get all their settings.
149 // This has the effect of bringing in the entire state of extension settings
150 // in memory; sad.
151 SyncDataList all_sync_data;
152 std::set<std::string> known_extension_ids;
153 GetKnownExtensionIDs(&known_extension_ids);
154
155 for (std::set<std::string>::const_iterator it = known_extension_ids.begin();
156 it != known_extension_ids.end(); ++it) {
157 ExtensionSettingsStorage::Result maybe_settings = GetStorage(*it)->Get();
158 if (maybe_settings.HasError()) {
159 LOG(WARNING) << "Failed to get settings for " << *it << ": " <<
160 maybe_settings.GetError();
161 continue;
162 }
163
164 DictionaryValue* settings = maybe_settings.GetSettings();
165 for (DictionaryValue::key_iterator key_it = settings->begin_keys();
166 key_it != settings->end_keys(); ++key_it) {
167 Value *value = NULL;
168 settings->GetWithoutPathExpansion(*key_it, &value);
169 all_sync_data.push_back(
170 extension_settings_sync_util::CreateData(*it, *key_it, *value));
171 }
172 }
173
174 return all_sync_data;
175 }
176
177 SyncError ExtensionSettings::MergeDataAndStartSyncing(
178 syncable::ModelType type,
179 const SyncDataList& initial_sync_data,
180 SyncChangeProcessor* sync_processor) {
181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
182 DCHECK_EQ(type, syncable::EXTENSION_SETTINGS);
183 DCHECK(!sync_processor_);
184 sync_processor_ = sync_processor;
185
186 // Group the initial sync data by extension id.
187 std::map<std::string, linked_ptr<DictionaryValue> > grouped_sync_data;
188 for (SyncDataList::const_iterator it = initial_sync_data.begin();
189 it != initial_sync_data.end(); ++it) {
190 ExtensionSettingSyncData data(*it);
191 linked_ptr<DictionaryValue> sync_data =
192 grouped_sync_data[data.extension_id()];
193 if (!sync_data.get()) {
194 sync_data = linked_ptr<DictionaryValue>(new DictionaryValue());
195 grouped_sync_data[data.extension_id()] = sync_data;
196 }
197 DCHECK(!sync_data->HasKey(data.key())) <<
198 "Duplicate settings for " << data.extension_id() << "/" << data.key();
199 sync_data->Set(data.key(), data.value().DeepCopy());
200 }
201
202 // Start syncing all existing storage areas. Any storage areas created in
203 // the future will start being synced as part of the creation process.
204 for (StorageObjMap::iterator it = storage_objs_.begin();
205 it != storage_objs_.end(); ++it) {
206 std::map<std::string, linked_ptr<DictionaryValue> >::iterator
207 maybe_sync_data = grouped_sync_data.find(it->first);
208 if (maybe_sync_data != grouped_sync_data.end()) {
209 it->second->StartSyncing(*maybe_sync_data->second, sync_processor);
akalin 2011/09/19 19:24:11 like above, use ignore_result and TODO
not at google - send to devlin 2011/09/20 07:59:36 Done.
210 grouped_sync_data.erase(it->first);
211 } else {
212 DictionaryValue empty;
213 it->second->StartSyncing(empty, sync_processor);
akalin 2011/09/19 19:24:11 ignore_result and TODO
not at google - send to devlin 2011/09/20 07:59:36 Done.
214 }
215 }
216
217 // Eagerly create and init the rest of the storage areas that have sync data.
218 // Under normal circumstances (i.e. not first-time sync) this will be all of
219 // them.
220 for (std::map<std::string, linked_ptr<DictionaryValue> >::iterator it =
221 grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) {
222 GetOrCreateStorageWithSyncData(it->first, *it->second);
223 }
224
225 return SyncError();
226 }
227
228 SyncError ExtensionSettings::ProcessSyncChanges(
229 const tracked_objects::Location& from_here,
230 const SyncChangeList& sync_changes) {
231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
232 DCHECK(sync_processor_);
233
234 // Group changes by extension, to pass all changes in a single method call.
235 std::map<std::string, ExtensionSettingSyncDataList> grouped_sync_data;
236 for (SyncChangeList::const_iterator it = sync_changes.begin();
237 it != sync_changes.end(); ++it) {
238 ExtensionSettingSyncData data(*it);
239 grouped_sync_data[data.extension_id()].push_back(data);
240 }
241
242 DictionaryValue empty;
243 for (std::map<std::string, ExtensionSettingSyncDataList>::iterator
244 it = grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) {
245 GetOrCreateStorageWithSyncData(it->first, empty)->
akalin 2011/09/19 19:24:11 ignore_result for errors, and TODO
not at google - send to devlin 2011/09/20 07:59:36 Done.
not at google - send to devlin 2011/09/20 07:59:36 Done.
246 ProcessSyncChanges(it->second);
247 }
248
249 return SyncError();
250 }
251
252 void ExtensionSettings::StopSyncing(syncable::ModelType type) {
253 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
254 DCHECK(sync_processor_);
255 sync_processor_ = NULL;
256
257 for (StorageObjMap::iterator it = storage_objs_.begin();
258 it != storage_objs_.end(); ++it) {
259 it->second->StopSyncing();
260 }
261 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698