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

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

Issue 7747043: WORK IN PROGRESS. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Small change Created 9 years, 4 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" 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/syncable_extension_settings_storage.h"
16 #include "third_party/leveldb/include/leveldb/iterator.h" 17 #include "third_party/leveldb/include/leveldb/iterator.h"
17 #include "third_party/leveldb/include/leveldb/write_batch.h" 18 #include "third_party/leveldb/include/leveldb/write_batch.h"
18 19
19 ExtensionSettings::ExtensionSettings(const FilePath& base_path) 20 ExtensionSettings::ExtensionSettings(const FilePath& base_path)
20 : base_path_(base_path) { 21 : base_path_(base_path), sync_processor_(NULL) {
21 } 22 }
22 23
23 ExtensionSettings::~ExtensionSettings() { 24 ExtensionSettings::~ExtensionSettings() {
24 std::map<std::string, ExtensionSettingsStorage*>::iterator it; 25 std::map<std::string, SyncableExtensionSettingsStorage*>::iterator it;
25 for (it = storage_objs_.begin(); it != storage_objs_.end(); ++it) { 26 for (it = storage_objs_.begin(); it != storage_objs_.end(); ++it) {
26 it->second->DeleteSoon(); 27 it->second->DeleteSoon();
27 } 28 }
28 } 29 }
29 30
30 void ExtensionSettings::GetStorage( 31 void ExtensionSettings::GetStorage(
31 const std::string& extension_id, 32 const std::string& extension_id,
32 const Callback& callback) { 33 const Callback& callback) {
33 if (!GetExistingStorage(extension_id, callback)) { 34 if (!GetExistingStorage(extension_id, callback)) {
34 StartCreationOfStorage( 35 StartCreationOfStorage(
(...skipping 10 matching lines...) Expand all
45 bool cached, 46 bool cached,
46 const std::string& extension_id, 47 const std::string& extension_id,
47 const Callback& callback) { 48 const Callback& callback) {
48 if (!GetExistingStorage(extension_id, callback)) { 49 if (!GetExistingStorage(extension_id, callback)) {
49 StartCreationOfStorage(extension_id, type, type, cached, callback); 50 StartCreationOfStorage(extension_id, type, type, cached, callback);
50 } 51 }
51 } 52 }
52 53
53 bool ExtensionSettings::GetExistingStorage( 54 bool ExtensionSettings::GetExistingStorage(
54 const std::string& extension_id, const Callback& callback) { 55 const std::string& extension_id, const Callback& callback) {
55 std::map<std::string, ExtensionSettingsStorage*>::iterator existing = 56 std::map<std::string, SyncableExtensionSettingsStorage*>::iterator existing =
56 storage_objs_.find(extension_id); 57 storage_objs_.find(extension_id);
57 if (existing == storage_objs_.end()) { 58 if (existing == storage_objs_.end()) {
58 // No existing storage. 59 // No existing storage.
59 return false; 60 return false;
60 } 61 }
61 // Existing storage. Reply with that. 62 // Existing storage. Reply with that.
62 ExtensionSettingsStorage* storage = existing->second; 63 SyncableExtensionSettingsStorage* storage = existing->second;
63 DCHECK(storage != NULL); 64 DCHECK(storage != NULL);
64 MessageLoop::current()->PostTask( 65 MessageLoop::current()->PostTask(
65 FROM_HERE, 66 FROM_HERE,
66 base::Bind( 67 base::Bind(
67 &ExtensionSettings::RunWithStorage, 68 &ExtensionSettings::RunWithStorage,
68 this, 69 this,
69 new Callback(callback), 70 new Callback(callback),
70 storage)); 71 storage));
71 return true; 72 return true;
72 } 73 }
73 74
74 void ExtensionSettings::RunWithStorage( 75 void ExtensionSettings::RunWithStorage(
75 Callback* callback, ExtensionSettingsStorage* storage) { 76 Callback* callback, SyncableExtensionSettingsStorage* storage) {
76 callback->Run(storage); 77 callback->Run(storage);
77 delete callback; 78 delete callback;
78 } 79 }
79 80
80 void ExtensionSettings::StartCreationOfStorage( 81 void ExtensionSettings::StartCreationOfStorage(
81 const std::string& extension_id, 82 const std::string& extension_id,
82 ExtensionSettingsStorage::Type type, 83 ExtensionSettingsStorage::Type type,
83 ExtensionSettingsStorage::Type fallback_type, 84 ExtensionSettingsStorage::Type fallback_type,
84 bool cached, 85 bool cached,
85 const Callback& callback) { 86 const Callback& callback) {
(...skipping 10 matching lines...) Expand all
96 callback)); 97 callback));
97 } 98 }
98 99
99 void ExtensionSettings::CreateStorageOnFileThread( 100 void ExtensionSettings::CreateStorageOnFileThread(
100 const std::string& extension_id, 101 const std::string& extension_id,
101 ExtensionSettingsStorage::Type type, 102 ExtensionSettingsStorage::Type type,
102 ExtensionSettingsStorage::Type fallback_type, 103 ExtensionSettingsStorage::Type fallback_type,
103 bool cached, 104 bool cached,
104 const Callback& callback) { 105 const Callback& callback) {
105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
106 ExtensionSettingsStorage* storage = CreateStorage(extension_id, type, cached); 107 SyncableExtensionSettingsStorage* storage =
108 CreateStorage(extension_id, type, cached);
107 if (storage == NULL && fallback_type != type) { 109 if (storage == NULL && fallback_type != type) {
108 storage = CreateStorage(extension_id, fallback_type, cached); 110 storage = CreateStorage(extension_id, fallback_type, cached);
109 } 111 }
110 DCHECK(storage != NULL); 112 DCHECK(storage != NULL);
111 BrowserThread::PostTask( 113 BrowserThread::PostTask(
112 BrowserThread::UI, 114 BrowserThread::UI,
113 FROM_HERE, 115 FROM_HERE,
114 base::Bind( 116 base::Bind(
115 &ExtensionSettings::EndCreationOfStorage, 117 &ExtensionSettings::EndCreationOfStorage,
116 this, 118 this,
117 extension_id, 119 extension_id,
118 storage, 120 storage,
119 callback)); 121 callback));
120 } 122 }
121 123
122 ExtensionSettingsStorage* ExtensionSettings::CreateStorage( 124 SyncableExtensionSettingsStorage* ExtensionSettings::CreateStorage(
123 const std::string& extension_id, 125 const std::string& extension_id,
124 ExtensionSettingsStorage::Type type, 126 ExtensionSettingsStorage::Type type,
125 bool cached) { 127 bool cached) {
126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 128 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
127 ExtensionSettingsStorage* storage = NULL; 129 ExtensionSettingsStorage* storage = NULL;
128 switch (type) { 130 switch (type) {
129 case ExtensionSettingsStorage::NOOP: 131 case ExtensionSettingsStorage::NOOP:
130 storage = new ExtensionSettingsNoopStorage(); 132 storage = new ExtensionSettingsNoopStorage();
131 break; 133 break;
132 case ExtensionSettingsStorage::LEVELDB: 134 case ExtensionSettingsStorage::LEVELDB:
133 storage = ExtensionSettingsLeveldbStorage::Create( 135 storage = ExtensionSettingsLeveldbStorage::Create(
134 base_path_, extension_id); 136 base_path_, extension_id);
135 break; 137 break;
136 default: 138 default:
137 NOTREACHED(); 139 NOTREACHED();
138 } 140 }
139 if (storage != NULL && cached) { 141 if (storage == NULL) {
142 return NULL;
143 }
144 if (cached) {
140 storage = new ExtensionSettingsStorageCache(storage); 145 storage = new ExtensionSettingsStorageCache(storage);
141 } 146 }
142 return storage; 147 // Always send changes to sync. The merge algorithm is such that local data
148 // will be overwritten by sync data, so even if it's purely in-memory storage
149 // the settings will be consistent across browser restarts.
150 return new SyncableExtensionSettingsStorage(extension_id, storage);
143 } 151 }
144 152
145 void ExtensionSettings::EndCreationOfStorage( 153 void ExtensionSettings::EndCreationOfStorage(
146 const std::string& extension_id, 154 const std::string& extension_id,
147 ExtensionSettingsStorage* storage, 155 SyncableExtensionSettingsStorage* storage,
148 const Callback& callback) { 156 const Callback& callback) {
149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
150 // Cache the result now. To avoid a race condition, check again to see 158 // Cache the result now. To avoid a race condition, check again to see
151 // whether a storage has been created already; if so, use that one. 159 // whether a storage has been created already; if so, use that one.
152 std::map<std::string, ExtensionSettingsStorage*>::iterator existing = 160 std::map<std::string, SyncableExtensionSettingsStorage*>::iterator existing =
153 storage_objs_.find(extension_id); 161 storage_objs_.find(extension_id);
154 if (existing == storage_objs_.end()) { 162 if (existing == storage_objs_.end()) {
155 storage_objs_[extension_id] = storage; 163 storage_objs_[extension_id] = storage;
156 } else { 164 } else {
157 storage->DeleteSoon(); 165 storage->DeleteSoon();
158 storage = existing->second; 166 storage = existing->second;
159 DCHECK(storage != NULL); 167 DCHECK(storage != NULL);
160 } 168 }
169 if (sync_processor_ != NULL) {
170 StartSyncingStorage(extension_id, storage);
171 }
161 callback.Run(storage); 172 callback.Run(storage);
162 } 173 }
174
175 SyncDataList ExtensionSettings::GetAllSyncData(
176 syncable::ModelType type) const {
177 // Not possible to do this synchronously, or while satisfying const, but only
178 // used for debugging so fine to ignore.
179 return SyncDataList();
180 }
181
182 SyncError ExtensionSettings::MergeDataAndStartSyncing(
183 syncable::ModelType type,
184 const SyncDataList& initial_sync_data,
185 SyncChangeProcessor* sync_processor) {
186 DCHECK(type == syncable::EXTENSION_SETTINGS);
187 DCHECK(sync_processor_ == NULL);
188 sync_processor_ = sync_processor;
189
190 // Unmerged sync data could conceivably be non-empty if this method is called
191 // in quick succession, before the storage creation methods return (clearing
192 // the data). Clearing the unmerged data here is safe, it will just get
193 // repopulated with the new and correct data.
194 std::map<std::string, DictionaryValue*>::iterator unmerged_it;
195 for (unmerged_it = unmerged_sync_data_.begin();
196 unmerged_it != unmerged_sync_data_.end(); ++unmerged_it) {
197 delete unmerged_it->second;
198 }
199 unmerged_sync_data_.clear();
200
201 // Merge algorithm when starting to sync: for each extension, if there are no
202 // sycned settings yet, push local settings to sync. Otherwise, completely
203 // overwrite local settings with those from sync.
204 //
205 // Firstly group the initial data per extension.
206 for (SyncDataList::const_iterator it = initial_sync_data.begin();
207 it != initial_sync_data.end(); ++it) {
208 ExtensionSettingsSyncData data(*it);
209 if (data.value() == NULL) {
210 LOG(WARNING) << "NULL value in sync data";
211 continue;
212 }
213 DictionaryValue* sync_data = unmerged_sync_data_[data.extension_id()];
214 if (sync_data == NULL) {
215 sync_data = new DictionaryValue();
216 unmerged_sync_data_[data.extension_id()] = sync_data;
217 }
218 DCHECK(!sync_data->HasKey(data.key())) <<
219 "Duplicate settings for " << data.extension_id() << "/" << data.key();
220 sync_data->Set(data.key(), data.value()->DeepCopy());
221 }
222
223 // Immediately push sync state to local for existing storage areas.
224 std::map<std::string, SyncableExtensionSettingsStorage*>::iterator storage_it;
225 for (storage_it = storage_objs_.begin();
226 storage_it != storage_objs_.end(); ++storage_it) {
227 StartSyncingStorage(storage_it->first, storage_it->second);
228 }
229
230 // Asynchronously push sync state to local for the remaining settings.
231 for (unmerged_it = unmerged_sync_data_.begin();
232 unmerged_it != unmerged_sync_data_.end(); ++unmerged_it) {
233 // StartSyncingStorage will be called from EndCreationOfStorage, so the
234 // actual callback from getting the storage doesn't need to do anything.
235 GetStorage(
236 unmerged_it->first,
237 base::Bind(
238 &ExtensionSettings::AssertNoSyncData,
239 this,
240 unmerged_it->first));
241 }
242
243 return SyncError();
244 }
245
246 void ExtensionSettings::AssertNoSyncData(
247 const std::string& extension_id,
248 SyncableExtensionSettingsStorage* storage) {
249 DCHECK_EQ(0u, unmerged_sync_data_.count(extension_id));
250 }
251
252 void ExtensionSettings::StartSyncingStorage(
253 const std::string& extension_id,
254 SyncableExtensionSettingsStorage* storage) {
255 DCHECK(sync_processor_ != NULL);
256 scoped_ptr<DictionaryValue> sync_data(unmerged_sync_data_[extension_id]);
257 unmerged_sync_data_.erase(extension_id);
258 if (sync_data.get() == NULL) {
259 DictionaryValue no_data;
260 storage->StartSyncing(no_data, sync_processor_);
261 } else {
262 storage->StartSyncing(*sync_data, sync_processor_);
263 }
264 }
265
266 static void CallProcessSyncChanges(
267 ExtensionSettingsSyncDataList* sync_changes,
268 SyncableExtensionSettingsStorage* storage) {
269 storage->ProcessSyncChanges(*sync_changes);
270 delete sync_changes;
271 }
272
273 SyncError ExtensionSettings::ProcessSyncChanges(
274 const tracked_objects::Location& from_here,
275 const SyncChangeList& sync_changes) {
276 DCHECK(sync_processor_ != NULL);
277
278 // Gather changes per extension, so that all the processing can be done from a
279 // single GetStorage() call.
280 std::map<std::string, ExtensionSettingsSyncDataList> all_sync_data;
281 for (SyncChangeList::const_iterator it = sync_changes.begin();
282 it != sync_changes.end(); ++it) {
283 ExtensionSettingsSyncData data(*it);
284 if (data.value() == NULL) {
285 LOG(WARNING) << "NULL value in sync data";
286 continue;
287 }
288 all_sync_data[data.extension_id()].push_back(data);
289 }
290
291 // Push changes to storage areas.
292 std::map<std::string, ExtensionSettingsSyncDataList>::iterator it;
293 for (it = all_sync_data.begin(); it != all_sync_data.end(); ++it) {
294 GetStorage(
295 it->first,
296 base::Bind(
297 &CallProcessSyncChanges,
298 new ExtensionSettingsSyncDataList(it->second)));
299 }
300
301 return SyncError();
302 }
303
304 void ExtensionSettings::StopSyncing(syncable::ModelType type) {
305 DCHECK(type == syncable::EXTENSION_SETTINGS);
306 DCHECK(sync_processor_ != NULL);
307 sync_processor_ = NULL;
308
309 std::map<std::string, SyncableExtensionSettingsStorage*>::iterator it;
310 for (it = storage_objs_.begin(); it != storage_objs_.end(); ++it) {
311 it->second->StopSyncing();
312 }
313 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698