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

Side by Side Diff: chrome/browser/extensions/settings/settings_frontend.cc

Issue 10784035: Refactored SettingsFrontend and forwarding of calls to the backends. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 5 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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/settings/settings_frontend.h" 5 #include "chrome/browser/extensions/settings/settings_frontend.h"
6 6
7 #include <limits>
8
7 #include "base/bind.h" 9 #include "base/bind.h"
8 #include "base/file_path.h" 10 #include "base/file_path.h"
9 #include "base/string_number_conversions.h" 11 #include "base/stl_util.h"
10 #include "chrome/browser/extensions/extension_event_names.h" 12 #include "chrome/browser/extensions/extension_event_names.h"
11 #include "chrome/browser/extensions/extension_event_router.h" 13 #include "chrome/browser/extensions/extension_event_router.h"
12 #include "chrome/browser/extensions/extension_service.h" 14 #include "chrome/browser/extensions/extension_service.h"
13 #include "chrome/browser/extensions/settings/leveldb_settings_storage_factory.h" 15 #include "chrome/browser/extensions/settings/leveldb_settings_storage_factory.h"
14 #include "chrome/browser/extensions/settings/settings_backend.h" 16 #include "chrome/browser/extensions/settings/settings_backend.h"
17 #include "chrome/browser/extensions/settings/settings_managed_frontend.h"
15 #include "chrome/browser/extensions/settings/settings_namespace.h" 18 #include "chrome/browser/extensions/settings/settings_namespace.h"
16 #include "chrome/browser/extensions/settings/weak_unlimited_settings_storage.h" 19 #include "chrome/browser/extensions/settings/settings_storage_frontend.h"
17 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/value_store/leveldb_value_store.h"
19 #include "chrome/common/extensions/api/storage.h" 21 #include "chrome/common/extensions/api/storage.h"
20 #include "content/public/browser/browser_thread.h" 22 #include "content/public/browser/browser_thread.h"
21 #include "content/public/browser/notification_service.h"
22 23
23 using content::BrowserThread; 24 using content::BrowserThread;
24 25
25 namespace extensions { 26 namespace extensions {
26 27
27 namespace { 28 namespace {
not at google - send to devlin 2012/07/18 07:46:18 Revisiting this file after going through the other
Joao da Silva 2012/07/18 21:40:25 So the ValueStoreCache interface has been extended
28 29
29 // Settings change Observer which forwards changes on to the extension 30 // Settings change Observer which forwards changes on to the extension
30 // processes for |profile| and its incognito partner if it exists. 31 // processes for |profile| and its incognito partner if it exists.
31 class DefaultObserver : public SettingsObserver { 32 class DefaultObserver : public SettingsObserver {
32 public: 33 public:
33 explicit DefaultObserver(Profile* profile) : profile_(profile) {} 34 explicit DefaultObserver(Profile* profile) : profile_(profile) {}
34 35
35 // SettingsObserver implementation. 36 // SettingsObserver implementation.
36 virtual void OnSettingsChanged( 37 virtual void OnSettingsChanged(
37 const std::string& extension_id, 38 const std::string& extension_id,
38 settings_namespace::Namespace settings_namespace, 39 settings_namespace::Namespace settings_namespace,
39 const std::string& change_json) OVERRIDE { 40 const std::string& change_json) OVERRIDE {
40 profile_->GetExtensionEventRouter()->DispatchEventToExtension( 41 profile_->GetExtensionEventRouter()->DispatchEventToExtension(
41 extension_id, 42 extension_id,
42 extension_event_names::kOnSettingsChanged, 43 extension_event_names::kOnSettingsChanged,
43 // This is the list of function arguments to pass to the onChanged 44 // This is the list of function arguments to pass to the onChanged
44 // handler of extensions, an array of [changes, settings_namespace]. 45 // handler of extensions, an array of [changes, settings_namespace].
45 std::string("[") + change_json + ",\"" + 46 std::string("[") + change_json + ",\"" +
46 settings_namespace::ToString(settings_namespace) + "\"]", 47 settings_namespace::ToString(settings_namespace) + "\"]",
47 NULL, 48 NULL,
48 GURL()); 49 GURL());
49 } 50 }
50 51
51 private: 52 private:
52 Profile* const profile_; 53 Profile* const profile_;
53 }; 54 };
54 55
55 void CallbackWithSyncableService(
56 const SettingsFrontend::SyncableServiceCallback& callback,
57 SettingsBackend* backend) {
58 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
59 callback.Run(backend);
60 }
61
62 void CallbackWithStorage(
63 const std::string& extension_id,
64 const SettingsFrontend::StorageCallback& callback,
65 SettingsBackend* backend) {
66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
67 callback.Run(backend->GetStorage(extension_id));
68 }
69
70 void CallbackWithNullStorage(
71 const SettingsFrontend::StorageCallback& callback) {
72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
73 callback.Run(NULL);
74 }
75
76 void DeleteStorageOnFileThread(
77 const std::string& extension_id, SettingsBackend* backend) {
78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
79 backend->DeleteStorage(extension_id);
80 }
81
82 void CallbackWithUnlimitedStorage(
83 const std::string& extension_id,
84 const SettingsFrontend::StorageCallback& callback,
85 SettingsBackend* backend) {
86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
87 WeakUnlimitedSettingsStorage unlimited_storage(
88 backend->GetStorage(extension_id));
89 callback.Run(&unlimited_storage);
90 }
91
92 SettingsStorageQuotaEnforcer::Limits GetLocalLimits() { 56 SettingsStorageQuotaEnforcer::Limits GetLocalLimits() {
93 SettingsStorageQuotaEnforcer::Limits limits = { 57 SettingsStorageQuotaEnforcer::Limits limits = {
94 static_cast<size_t>(api::storage::local::QUOTA_BYTES), 58 static_cast<size_t>(api::storage::local::QUOTA_BYTES),
95 std::numeric_limits<size_t>::max(), 59 std::numeric_limits<size_t>::max(),
96 std::numeric_limits<size_t>::max() 60 std::numeric_limits<size_t>::max()
97 }; 61 };
98 return limits; 62 return limits;
99 } 63 }
100 64
101 SettingsStorageQuotaEnforcer::Limits GetSyncLimits() { 65 SettingsStorageQuotaEnforcer::Limits GetSyncLimits() {
102 SettingsStorageQuotaEnforcer::Limits limits = { 66 SettingsStorageQuotaEnforcer::Limits limits = {
103 static_cast<size_t>(api::storage::sync::QUOTA_BYTES), 67 static_cast<size_t>(api::storage::sync::QUOTA_BYTES),
104 static_cast<size_t>(api::storage::sync::QUOTA_BYTES_PER_ITEM), 68 static_cast<size_t>(api::storage::sync::QUOTA_BYTES_PER_ITEM),
105 static_cast<size_t>(api::storage::sync::MAX_ITEMS) 69 static_cast<size_t>(api::storage::sync::MAX_ITEMS)
106 }; 70 };
107 return limits; 71 return limits;
108 } 72 }
109 73
110 } // namespace 74 } // namespace
111 75
112 // Ref-counted container for a SettingsBackend object.
113 class SettingsFrontend::BackendWrapper
114 : public base::RefCountedThreadSafe<BackendWrapper> {
115 public:
116 // Creates a new BackendWrapper and initializes it on the FILE thread.
117 static scoped_refptr<BackendWrapper> CreateAndInit(
118 const scoped_refptr<SettingsStorageFactory>& factory,
119 const SettingsStorageQuotaEnforcer::Limits& quota,
120 const scoped_refptr<SettingsObserverList>& observers,
121 const FilePath& path) {
122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
123 scoped_refptr<BackendWrapper> backend_wrapper =
124 new BackendWrapper(factory, quota, observers);
125 BrowserThread::PostTask(
126 BrowserThread::FILE,
127 FROM_HERE,
128 base::Bind(
129 &SettingsFrontend::BackendWrapper::InitOnFileThread,
130 backend_wrapper,
131 path));
132 return backend_wrapper;
133 }
134
135 typedef base::Callback<void(SettingsBackend*)> BackendCallback;
136
137 // Runs |callback| with the wrapped Backend on the FILE thread.
138 void RunWithBackend(const BackendCallback& callback) {
139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
140 BrowserThread::PostTask(
141 BrowserThread::FILE,
142 FROM_HERE,
143 base::Bind(
144 &SettingsFrontend::BackendWrapper::RunWithBackendOnFileThread,
145 this,
146 callback));
147 }
148
149 SettingsBackend* GetBackend() const {
150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
151 return backend_;
152 }
153
154 private:
155 friend class base::RefCountedThreadSafe<BackendWrapper>;
156
157 BackendWrapper(
158 const scoped_refptr<SettingsStorageFactory>& storage_factory,
159 const SettingsStorageQuotaEnforcer::Limits& quota,
160 const scoped_refptr<SettingsObserverList>& observers)
161 : storage_factory_(storage_factory),
162 quota_(quota),
163 observers_(observers),
164 backend_(NULL) {
165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
166 }
167
168 virtual ~BackendWrapper() {
169 if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
170 delete backend_;
171 } else if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
172 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, backend_);
173 } else {
174 NOTREACHED();
175 }
176 }
177
178 void InitOnFileThread(const FilePath& path) {
179 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
180 DCHECK(!backend_);
181 backend_ = new SettingsBackend(storage_factory_, path, quota_, observers_);
182 storage_factory_ = NULL;
183 observers_ = NULL;
184 }
185
186 void RunWithBackendOnFileThread(const BackendCallback& callback) {
187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
188 DCHECK(backend_);
189 callback.Run(backend_);
190 }
191
192 // Only need these until |backend_| exists.
193 scoped_refptr<SettingsStorageFactory> storage_factory_;
194 const SettingsStorageQuotaEnforcer::Limits quota_;
195 scoped_refptr<SettingsObserverList> observers_;
196
197 // Wrapped Backend. Used exclusively on the FILE thread, and is created on
198 // the FILE thread in InitOnFileThread.
199 SettingsBackend* backend_;
200
201 DISALLOW_COPY_AND_ASSIGN(BackendWrapper);
202 };
203
204 // SettingsFrontend
205
206 // static 76 // static
207 SettingsFrontend* SettingsFrontend::Create(Profile* profile) { 77 SettingsFrontend* SettingsFrontend::Create(Profile* profile) {
208 return new SettingsFrontend(new LeveldbSettingsStorageFactory(), profile); 78 return new SettingsFrontend(new LeveldbSettingsStorageFactory(), profile);
209 } 79 }
210 80
211 // static 81 // static
212 SettingsFrontend* SettingsFrontend::Create( 82 SettingsFrontend* SettingsFrontend::Create(
213 const scoped_refptr<SettingsStorageFactory>& storage_factory, 83 const scoped_refptr<SettingsStorageFactory>& storage_factory,
214 Profile* profile) { 84 Profile* profile) {
215 return new SettingsFrontend(storage_factory, profile); 85 return new SettingsFrontend(storage_factory, profile);
216 } 86 }
217 87
218 SettingsFrontend::SettingsFrontend( 88 SettingsFrontend::SettingsFrontend(
219 const scoped_refptr<SettingsStorageFactory>& factory, Profile* profile) 89 const scoped_refptr<SettingsStorageFactory>& factory, Profile* profile)
220 : local_quota_limit_(GetLocalLimits()), 90 : local_quota_limit_(GetLocalLimits()),
221 sync_quota_limit_(GetSyncLimits()), 91 sync_quota_limit_(GetSyncLimits()),
222 profile_(profile), 92 profile_(profile),
223 observers_(new SettingsObserverList()), 93 observers_(new SettingsObserverList()),
224 profile_observer_(new DefaultObserver(profile)) { 94 profile_observer_(new DefaultObserver(profile)) {
225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
226 DCHECK(!profile->IsOffTheRecord()); 96 DCHECK(!profile->IsOffTheRecord());
227 97
228 observers_->AddObserver(profile_observer_.get()); 98 observers_->AddObserver(profile_observer_.get());
229 99
230 const FilePath& profile_path = profile->GetPath(); 100 const FilePath& profile_path = profile->GetPath();
231 backends_[settings_namespace::LOCAL].app = 101 frontends_[settings_namespace::LOCAL] =
232 BackendWrapper::CreateAndInit( 102 new SettingsStorageFrontend(
103 settings_namespace::LOCAL,
233 factory, 104 factory,
234 local_quota_limit_, 105 local_quota_limit_,
235 observers_, 106 observers_,
236 profile_path.AppendASCII( 107 profile_path);
237 ExtensionService::kLocalAppSettingsDirectoryName)); 108 sync_frontend_ =
not at google - send to devlin 2012/07/18 07:46:18 Having this as a member variable *and* in the map
Joao da Silva 2012/07/18 21:40:25 The purpose of this pointer was precisely to avoid
238 backends_[settings_namespace::LOCAL].extension = 109 new SettingsStorageFrontend(
239 BackendWrapper::CreateAndInit( 110 settings_namespace::SYNC,
240 factory,
241 local_quota_limit_,
242 observers_,
243 profile_path.AppendASCII(
244 ExtensionService::kLocalExtensionSettingsDirectoryName));
245 backends_[settings_namespace::SYNC].app =
246 BackendWrapper::CreateAndInit(
247 factory, 111 factory,
248 sync_quota_limit_, 112 sync_quota_limit_,
249 observers_, 113 observers_,
250 profile_path.AppendASCII( 114 profile_path);
251 ExtensionService::kSyncAppSettingsDirectoryName)); 115 frontends_[settings_namespace::SYNC] = sync_frontend_;
252 backends_[settings_namespace::SYNC].extension = 116 frontends_[settings_namespace::MANAGED] =
253 BackendWrapper::CreateAndInit( 117 new SettingsManagedFrontend(profile);
254 factory,
255 sync_quota_limit_,
256 observers_,
257 profile_path.AppendASCII(
258 ExtensionService::kSyncExtensionSettingsDirectoryName));
259 } 118 }
260 119
261 SettingsFrontend::~SettingsFrontend() { 120 SettingsFrontend::~SettingsFrontend() {
262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
263 observers_->RemoveObserver(profile_observer_.get()); 122 observers_->RemoveObserver(profile_observer_.get());
123 STLDeleteValues(&frontends_);
not at google - send to devlin 2012/07/18 07:46:18 I prefer making frontend_ contain linked_ptrs rath
Joao da Silva 2012/07/18 21:40:25 Done.
264 } 124 }
265 125
266 syncer::SyncableService* SettingsFrontend::GetBackendForSync( 126 syncer::SyncableService* SettingsFrontend::GetBackendForSync(
267 syncer::ModelType type) const { 127 syncer::ModelType type) const {
268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 128 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
269 std::map<settings_namespace::Namespace, BackendWrappers>::const_iterator
270 sync_backends = backends_.find(settings_namespace::SYNC);
271 DCHECK(sync_backends != backends_.end());
272 switch (type) { 129 switch (type) {
273 case syncer::APP_SETTINGS: 130 case syncer::APP_SETTINGS:
274 return sync_backends->second.app->GetBackend(); 131 return sync_frontend_->GetAppBackend();
275 case syncer::EXTENSION_SETTINGS: 132 case syncer::EXTENSION_SETTINGS:
276 return sync_backends->second.extension->GetBackend(); 133 return sync_frontend_->GetExtensionBackend();
277 default: 134 default:
278 NOTREACHED(); 135 NOTREACHED();
279 return NULL; 136 return NULL;
280 } 137 }
281 } 138 }
282 139
283 void SettingsFrontend::RunWithStorage( 140 void SettingsFrontend::RunWithStorage(
284 const std::string& extension_id, 141 const std::string& extension_id,
285 settings_namespace::Namespace settings_namespace, 142 settings_namespace::Namespace settings_namespace,
286 const StorageCallback& callback) { 143 const SettingsNamespaceFrontend::StorageCallback& callback) {
287 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
288 145
146 SettingsNamespaceFrontend* frontend = frontends_[settings_namespace];
147 DCHECK(frontend);
not at google - send to devlin 2012/07/18 07:46:18 CHECK not DCHECK
Joao da Silva 2012/07/18 21:40:25 The idea was to make this fail silently in release
148
289 const Extension* extension = 149 const Extension* extension =
290 profile_->GetExtensionService()->GetExtensionById(extension_id, true); 150 profile_->GetExtensionService()->GetExtensionById(extension_id, true);
291 if (!extension) { 151 if (!extension || !frontend) {
not at google - send to devlin 2012/07/18 07:46:18 !frontend check should be unnecessary
Joao da Silva 2012/07/18 21:40:25 Done.
292 BrowserThread::PostTask( 152 callback.Run(NULL);
not at google - send to devlin 2012/07/18 07:46:18 The reason for CallbackWithNullStorage is so that
Joao da Silva 2012/07/18 21:40:25 Thanks for clarifying this issue. Done.
293 BrowserThread::FILE,
294 FROM_HERE,
295 base::Bind(&CallbackWithNullStorage, callback));
296 return; 153 return;
297 } 154 }
298 155
299 // A neat way to implement unlimited storage; if the extension has the 156 frontend->RunWithStorage(extension, callback);
300 // unlimited storage permission, force through all calls to Set() (in the
301 // same way that writes from sync ignore quota).
302 // But only if it's local storage (bad stuff would happen if sync'ed
303 // storage is allowed to be unlimited).
304 bool is_unlimited =
305 settings_namespace == settings_namespace::LOCAL &&
306 extension->HasAPIPermission(APIPermission::kUnlimitedStorage);
307
308 scoped_refptr<BackendWrapper> backend;
309 if (extension->is_app()) {
310 backend = backends_[settings_namespace].app;
311 } else {
312 backend = backends_[settings_namespace].extension;
313 }
314
315 backend->RunWithBackend(
316 base::Bind(
317 is_unlimited ?
318 &CallbackWithUnlimitedStorage : &CallbackWithStorage,
319 extension_id,
320 callback));
321 } 157 }
322 158
323 void SettingsFrontend::DeleteStorageSoon( 159 void SettingsFrontend::DeleteStorageSoon(
324 const std::string& extension_id) { 160 const std::string& extension_id) {
325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
326 SettingsFrontend::BackendWrapper::BackendCallback callback = 162 for (FrontendMap::iterator it = frontends_.begin();
327 base::Bind(&DeleteStorageOnFileThread, extension_id); 163 it != frontends_.end(); ++it) {
328 for (std::map<settings_namespace::Namespace, BackendWrappers>::iterator it = 164 it->second->DeleteStorageSoon(extension_id);
329 backends_.begin(); it != backends_.end(); ++it) {
330 it->second.app->RunWithBackend(callback);
331 it->second.extension->RunWithBackend(callback);
332 } 165 }
333 } 166 }
334 167
335 scoped_refptr<SettingsObserverList> SettingsFrontend::GetObservers() { 168 scoped_refptr<SettingsObserverList> SettingsFrontend::GetObservers() {
336 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
337 return observers_; 170 return observers_;
338 } 171 }
339 172
340 // BackendWrappers
341
342 SettingsFrontend::BackendWrappers::BackendWrappers() {}
343 SettingsFrontend::BackendWrappers::~BackendWrappers() {}
344
345 } // namespace extensions 173 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698