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

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 #1 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"
akalin 2011/09/15 19:56:44 no need for bind
not at google - send to devlin 2011/09/16 05:18:59 Done.
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 extension_service_(NULL),
25 sync_processor_(NULL) {}
akalin 2011/09/15 19:56:44 add DCHECK for FILE thread
not at google - send to devlin 2011/09/16 05:18:59 ... except it doesn't need to be constructed on th
akalin 2011/09/16 15:36:40 An object which is constructed/destroyed on one th
not at google - send to devlin 2011/09/19 07:10:46 I don't see why it can't be understood by itself.
21 26
22 ExtensionSettings::~ExtensionSettings() { 27 ExtensionSettings::~ExtensionSettings() {
23 std::map<std::string, ExtensionSettingsStorage*>::iterator it; 28 std::map<std::string, SyncableExtensionSettingsStorage*>::iterator it;
akalin 2011/09/15 19:56:44 add DCHECK for FILE thread
not at google - send to devlin 2011/09/16 05:18:59 Ditto above comment, which is why they're deleted
akalin 2011/09/16 15:36:40 See earlier comment. If this class lives complete
not at google - send to devlin 2011/09/19 07:10:46 Yep, I made this change in the version I uploaded
24 for (it = storage_objs_.begin(); it != storage_objs_.end(); ++it) { 29 for (it = storage_objs_.begin(); it != storage_objs_.end(); ++it) {
25 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, it->second); 30 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, it->second);
26 } 31 }
27 } 32 }
28 33
34 void ExtensionSettings::SetExtensionService(
35 ExtensionServiceInterface* extension_service) {
36 extension_service_ = extension_service;
37 }
38
29 ExtensionSettingsStorage* ExtensionSettings::GetStorage( 39 ExtensionSettingsStorage* ExtensionSettings::GetStorage(
30 const std::string& extension_id) { 40 const std::string& extension_id) const {
31 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 41 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
42 DictionaryValue empty;
akalin 2011/09/15 19:56:44 i prefer just inlining this, e.g. return GetOrCre
not at google - send to devlin 2011/09/16 05:18:59 Ah right. Yes, I would do that but DictionaryValu
akalin 2011/09/16 15:36:40 Right, I forgot about that. Ugh.
43 return GetOrCreateStorageWithSyncData(extension_id, empty);
44 }
32 45
33 std::map<std::string, ExtensionSettingsStorage*>::iterator existing = 46 SyncableExtensionSettingsStorage*
34 storage_objs_.find(extension_id); 47 ExtensionSettings::GetOrCreateStorageWithSyncData(
35 if (existing != storage_objs_.end()) { 48 const std::string& extension_id, const DictionaryValue& sync_data) const {
36 return existing->second; 49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
50 SyncableExtensionSettingsStorage* storage = GetOrCreateAndInitStorage(
51 ExtensionSettingsStorage::LEVELDB,
52 true,
53 extension_id,
54 sync_data);
55 if (!storage) {
akalin 2011/09/15 19:56:44 What happens in this case? That means that the se
not at google - send to devlin 2011/09/16 05:18:59 I thought about this earlier, and I think it's fin
56 // Fall back to an in-memory storage area (cached NOOP).
57 storage = GetOrCreateAndInitStorage(
58 ExtensionSettingsStorage::NOOP,
59 true,
60 extension_id,
61 sync_data);
62 DCHECK(storage);
37 } 63 }
38 64 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 } 65 }
52 66
53 ExtensionSettingsStorage* ExtensionSettings::GetStorageForTesting( 67 ExtensionSettingsStorage* ExtensionSettings::GetStorageForTesting(
54 ExtensionSettingsStorage::Type type, 68 ExtensionSettingsStorage::Type type,
55 bool cached, 69 bool cached,
56 const std::string& extension_id) { 70 const std::string& extension_id) const {
57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
72 DictionaryValue empty;
73 ExtensionSettingsStorage* storage =
74 GetOrCreateAndInitStorage(type, cached, extension_id, empty);
75 DCHECK(storage);
76 return storage;
77 }
58 78
59 std::map<std::string, ExtensionSettingsStorage*>::iterator existing = 79 SyncableExtensionSettingsStorage* ExtensionSettings::GetOrCreateAndInitStorage(
80 ExtensionSettingsStorage::Type type,
81 bool cached,
82 const std::string& extension_id,
83 const DictionaryValue& initial_sync_data) const {
84 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
85 std::map<std::string, SyncableExtensionSettingsStorage*>::iterator existing =
60 storage_objs_.find(extension_id); 86 storage_objs_.find(extension_id);
61 if (existing != storage_objs_.end()) { 87 if (existing != storage_objs_.end()) {
62 return existing->second; 88 return existing->second;
63 } 89 }
64 90 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 } 91 }
71 92
72 ExtensionSettingsStorage* ExtensionSettings::CreateStorage( 93 SyncableExtensionSettingsStorage* ExtensionSettings::CreateAndInitStorage(
94 ExtensionSettingsStorage::Type type,
95 bool cached,
73 const std::string& extension_id, 96 const std::string& extension_id,
74 ExtensionSettingsStorage::Type type, 97 const DictionaryValue& initial_sync_data) const {
75 bool cached) {
76 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
99 DCHECK(storage_objs_.count(extension_id) == 0);
akalin 2011/09/15 19:56:44 DCHECK_EQ
not at google - send to devlin 2011/09/16 05:18:59 Done.
77 ExtensionSettingsStorage* storage = NULL; 100 ExtensionSettingsStorage* storage = NULL;
78 switch (type) { 101 switch (type) {
79 case ExtensionSettingsStorage::NOOP: 102 case ExtensionSettingsStorage::NOOP:
80 storage = new ExtensionSettingsNoopStorage(); 103 storage = new ExtensionSettingsNoopStorage();
81 break; 104 break;
82 case ExtensionSettingsStorage::LEVELDB: 105 case ExtensionSettingsStorage::LEVELDB:
83 storage = ExtensionSettingsLeveldbStorage::Create( 106 storage = ExtensionSettingsLeveldbStorage::Create(
84 base_path_, extension_id); 107 base_path_, extension_id);
85 break; 108 break;
86 default: 109 default:
87 NOTREACHED(); 110 NOTREACHED();
88 } 111 }
89 if (storage != NULL && cached) { 112 if (!storage) {
113 return NULL;
114 }
115 if (cached) {
90 storage = new ExtensionSettingsStorageCache(storage); 116 storage = new ExtensionSettingsStorageCache(storage);
91 } 117 }
92 return storage; 118
119 SyncableExtensionSettingsStorage* synced_storage =
120 new SyncableExtensionSettingsStorage(extension_id, storage);
121 if (sync_processor_) {
122 synced_storage->StartSyncing(initial_sync_data, sync_processor_);
123 }
124 storage_objs_[extension_id] = synced_storage;
125 return synced_storage;
93 } 126 }
127
128 SyncDataList ExtensionSettings::GetAllSyncData(
129 syncable::ModelType type) const {
130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
131 DCHECK_EQ(type, syncable::EXTENSION_SETTINGS);
132 DCHECK(extension_service_);
133
134 // For all extensions, get all their settings.
135 // This has the effect of bringing in the entire state of extension settings
136 // in memory; sad.
137 SyncDataList all_sync_data;
akalin 2011/09/15 19:56:44 I think the logic that gathers all the extensions
not at google - send to devlin 2011/09/16 05:18:59 Done.
138 AppendAllSyncData(&all_sync_data, *extension_service_->extensions());
139 AppendAllSyncData(&all_sync_data,
140 *extension_service_->disabled_extensions());
141 AppendAllSyncData(&all_sync_data,
142 *extension_service_->terminated_extensions());
143 return all_sync_data;
144 }
145
146 void ExtensionSettings::AppendAllSyncData(
147 SyncDataList* sync_data, const ExtensionList& extensions) const {
148 for (ExtensionList::const_iterator it = extensions.begin();
akalin 2011/09/15 19:56:44 DCHECK, file thread
not at google - send to devlin 2011/09/16 05:18:59 Done.
149 it != extensions.end(); ++it) {
150 std::string extension_id = (*it)->id();
151 ExtensionSettingsStorage::Result maybe_settings =
152 GetStorage(extension_id)->Get();
153 if (maybe_settings.HasError()) {
154 LOG(WARNING) << "Failed to get settings for " << extension_id << ": " <<
155 maybe_settings.GetError();
156 continue;
157 }
158
159 DictionaryValue* settings = maybe_settings.GetSettings();
160 for (DictionaryValue::key_iterator key_it = settings->begin_keys();
161 key_it != settings->end_keys(); ++key_it) {
162 Value *value;
akalin 2011/09/15 19:56:44 = NULL
not at google - send to devlin 2011/09/16 05:18:59 Done.
163 settings->GetWithoutPathExpansion(*key_it, &value);
164 sync_data->push_back(
165 extension_settings_sync_util::CreateData(
166 extension_id, *key_it, *value));
167 }
168 }
169 }
170
171 SyncError ExtensionSettings::MergeDataAndStartSyncing(
172 syncable::ModelType type,
173 const SyncDataList& initial_sync_data,
174 SyncChangeProcessor* sync_processor) {
175 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
176 DCHECK_EQ(type, syncable::EXTENSION_SETTINGS);
177 DCHECK(!sync_processor_);
178 sync_processor_ = sync_processor;
179
180 // Group the initial sync data by extension id.
181 std::map<std::string, linked_ptr<DictionaryValue> > grouped_sync_data;
182 for (SyncDataList::const_iterator it = initial_sync_data.begin();
183 it != initial_sync_data.end(); ++it) {
184 ExtensionSettingSyncData data(*it);
185 if (!data.value()) {
186 LOG(WARNING) << "NULL value in sync data";
akalin 2011/09/15 19:56:44 prefer LOG(WARNING) << "Could not parse setting:
not at google - send to devlin 2011/09/16 05:18:59 Changing Value* to Value& made this moot. Which i
187 continue;
188 }
189 linked_ptr<DictionaryValue> sync_data =
190 grouped_sync_data[data.extension_id()];
191 if (!sync_data.get()) {
192 sync_data = linked_ptr<DictionaryValue>(new DictionaryValue());
193 grouped_sync_data[data.extension_id()] = sync_data;
194 }
195 DCHECK(!sync_data->HasKey(data.key())) <<
196 "Duplicate settings for " << data.extension_id() << "/" << data.key();
197 sync_data->Set(data.key(), data.value()->DeepCopy());
198 }
199
200 // Start syncing all existing storage areas. Any storage areas created in
201 // the future will start being synced as part of the creation process.
202 for (std::map<std::string, SyncableExtensionSettingsStorage*>::iterator it =
203 storage_objs_.begin(); it != storage_objs_.end(); ++it) {
204 linked_ptr<DictionaryValue> sync_data = grouped_sync_data[it->first];
akalin 2011/09/16 15:36:40 prefer using group_sync_data.find() so that you do
not at google - send to devlin 2011/09/19 07:10:46 Done.
205 if (sync_data.get()) {
206 it->second->StartSyncing(*sync_data, sync_processor);
207 } else {
akalin 2011/09/15 19:56:44 from the logic above, I don't think sync_data shou
not at google - send to devlin 2011/09/16 05:18:59 I think it can be NULL if sync data exists for sto
akalin 2011/09/16 15:36:40 Ah, I see, right.
208 DictionaryValue empty;
209 it->second->StartSyncing(empty, sync_processor);
210 }
211 grouped_sync_data.erase(it->first);
akalin 2011/09/15 19:56:44 no need for this, and in fact it's dangerous given
not at google - send to devlin 2011/09/16 05:18:59 Should be safe, I'm incrementing an iterator to st
akalin 2011/09/16 15:36:40 My mistake, I didn't see you were iterating over s
not at google - send to devlin 2011/09/19 07:10:46 Done.
212 }
213
214 // Eagerly create and init the rest of the storage areas that have sync data.
215 // Under normal circumstances (i.e. not first-time sync) this will be all of
216 // them.
217 for (std::map<std::string, linked_ptr<DictionaryValue> >::iterator it =
218 grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) {
219 GetOrCreateStorageWithSyncData(it->first, *it->second);
220 }
221
222 return SyncError();
223 }
224
225 SyncError ExtensionSettings::ProcessSyncChanges(
226 const tracked_objects::Location& from_here,
227 const SyncChangeList& sync_changes) {
228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
229 DCHECK(sync_processor_);
230
231 // Group changes by extension, to pass all changes in a single method call.
232 std::map<std::string, ExtensionSettingSyncDataList> grouped_sync_data;
233 for (SyncChangeList::const_iterator it = sync_changes.begin();
234 it != sync_changes.end(); ++it) {
235 ExtensionSettingSyncData data(*it);
236 if (!data.value()) {
237 LOG(WARNING) << "NULL value in sync data";
akalin 2011/09/15 19:56:44 revamp error message as above (possibly decomp int
not at google - send to devlin 2011/09/16 05:18:59 Done.
238 continue;
239 }
240 grouped_sync_data[data.extension_id()].push_back(data);
241 }
242
243 std::map<std::string, ExtensionSettingSyncDataList>::iterator it;
akalin 2011/09/15 19:56:44 move into for loop
not at google - send to devlin 2011/09/16 05:18:59 Done.
244 DictionaryValue empty;
245 for (it = grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) {
246 GetOrCreateStorageWithSyncData(it->first, empty)->
247 ProcessSyncChanges(it->second);
248 }
249
250 return SyncError();
251 }
252
253 void ExtensionSettings::StopSyncing(syncable::ModelType type) {
254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
255 DCHECK(sync_processor_);
256 sync_processor_ = NULL;
257
258 std::map<std::string, SyncableExtensionSettingsStorage*>::iterator it;
akalin 2011/09/15 19:56:44 fold into for loop
not at google - send to devlin 2011/09/16 05:18:59 Done.
259 for (it = storage_objs_.begin(); it != storage_objs_.end(); ++it) {
260 it->second->StopSyncing();
261 }
262 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698