OLD | NEW |
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/settings/settings_frontend.h" | 5 #include "chrome/browser/extensions/settings/settings_frontend.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/file_path.h" | 8 #include "base/file_path.h" |
9 #include "chrome/browser/extensions/extension_event_names.h" | 9 #include "chrome/browser/extensions/extension_event_names.h" |
10 #include "chrome/browser/extensions/extension_event_router.h" | 10 #include "chrome/browser/extensions/extension_event_router.h" |
11 #include "chrome/browser/extensions/extension_service.h" | 11 #include "chrome/browser/extensions/extension_service.h" |
12 #include "chrome/browser/extensions/settings/settings_backend.h" | 12 #include "chrome/browser/extensions/settings/settings_backend.h" |
| 13 #include "chrome/browser/extensions/settings/settings_namespace.h" |
13 #include "chrome/browser/extensions/settings/settings_leveldb_storage.h" | 14 #include "chrome/browser/extensions/settings/settings_leveldb_storage.h" |
14 #include "chrome/browser/profiles/profile.h" | 15 #include "chrome/browser/profiles/profile.h" |
15 #include "content/public/browser/browser_thread.h" | 16 #include "content/public/browser/browser_thread.h" |
16 #include "content/public/browser/notification_service.h" | 17 #include "content/public/browser/notification_service.h" |
17 | 18 |
| 19 using content::BrowserThread; |
| 20 |
18 namespace extensions { | 21 namespace extensions { |
19 | 22 |
20 using content::BrowserThread; | |
21 | |
22 namespace { | 23 namespace { |
23 | 24 |
24 struct Backends { | 25 // Settings change Observer which forwards changes on to the extension |
25 Backends( | 26 // processes for |profile| and its incognito partner if it exists. |
26 // Ownership taken. | 27 class DefaultObserver : public SettingsObserver { |
27 SettingsStorageFactory* storage_factory, | 28 public: |
28 const FilePath& profile_path, | 29 explicit DefaultObserver(Profile* profile) : profile_(profile) {} |
29 const scoped_refptr<SettingsObserverList>& observers) | |
30 : storage_factory_(storage_factory), | |
31 extensions_backend_( | |
32 storage_factory, | |
33 profile_path.AppendASCII( | |
34 ExtensionService::kExtensionSettingsDirectoryName), | |
35 observers), | |
36 apps_backend_( | |
37 storage_factory, | |
38 profile_path.AppendASCII( | |
39 ExtensionService::kAppSettingsDirectoryName), | |
40 observers) {} | |
41 | 30 |
42 scoped_ptr<SettingsStorageFactory> storage_factory_; | 31 // SettingsObserver implementation. |
43 SettingsBackend extensions_backend_; | 32 virtual void OnSettingsChanged( |
44 SettingsBackend apps_backend_; | 33 const std::string& extension_id, |
| 34 settings_namespace::Namespace settings_namespace, |
| 35 const std::string& change_json) OVERRIDE { |
| 36 profile_->GetExtensionEventRouter()->DispatchEventToExtension( |
| 37 extension_id, |
| 38 extension_event_names::kOnSettingsChanged, |
| 39 // This is the list of function arguments to pass to the onChanged |
| 40 // handler of extensions, an array of [changes, settings_namespace]. |
| 41 std::string("[") + change_json + ",\"" + |
| 42 settings_namespace::ToString(settings_namespace) + "\"]", |
| 43 NULL, |
| 44 GURL()); |
| 45 } |
| 46 |
| 47 private: |
| 48 Profile* const profile_; |
45 }; | 49 }; |
46 | 50 |
47 static void CallbackWithExtensionsBackend( | 51 void CallbackWithSyncableService( |
48 const SettingsFrontend::SyncableServiceCallback& callback, | 52 const SettingsFrontend::SyncableServiceCallback& callback, |
49 Backends* backends) { | 53 SettingsBackend* backend) { |
50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
51 callback.Run(&backends->extensions_backend_); | 55 callback.Run(backend); |
52 } | 56 } |
53 | 57 |
54 void CallbackWithAppsBackend( | 58 void CallbackWithStorage( |
55 const SettingsFrontend::SyncableServiceCallback& callback, | |
56 Backends* backends) { | |
57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
58 callback.Run(&backends->apps_backend_); | |
59 } | |
60 | |
61 void CallbackWithExtensionsStorage( | |
62 const std::string& extension_id, | 59 const std::string& extension_id, |
63 const SettingsFrontend::StorageCallback& callback, | 60 const SettingsFrontend::StorageCallback& callback, |
64 Backends* backends) { | 61 SettingsBackend* backend) { |
65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 62 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
66 callback.Run(backends->extensions_backend_.GetStorage(extension_id)); | 63 callback.Run(backend->GetStorage(extension_id)); |
67 } | |
68 | |
69 void CallbackWithAppsStorage( | |
70 const std::string& extension_id, | |
71 const SettingsFrontend::StorageCallback& callback, | |
72 Backends* backends) { | |
73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
74 callback.Run(backends->apps_backend_.GetStorage(extension_id)); | |
75 } | 64 } |
76 | 65 |
77 void CallbackWithNullStorage( | 66 void CallbackWithNullStorage( |
78 const SettingsFrontend::StorageCallback& callback) { | 67 const SettingsFrontend::StorageCallback& callback) { |
79 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 68 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
80 callback.Run(NULL); | 69 callback.Run(NULL); |
81 } | 70 } |
82 | 71 |
83 void DeleteStorageOnFileThread( | 72 void DeleteStorageOnFileThread( |
84 const std::string& extension_id, Backends* backends) { | 73 const std::string& extension_id, SettingsBackend* backend) { |
85 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
86 backends->extensions_backend_.DeleteStorage(extension_id); | 75 backend->DeleteStorage(extension_id); |
87 backends->apps_backend_.DeleteStorage(extension_id); | |
88 } | 76 } |
89 | 77 |
90 } // namespace | 78 } // namespace |
91 | 79 |
92 // DefaultObserver | 80 // Ref-counted container for a SettingsBackend object. |
93 | 81 class SettingsFrontend::BackendWrapper |
94 SettingsFrontend::DefaultObserver::DefaultObserver(Profile* profile) | 82 : public base::RefCountedThreadSafe<BackendWrapper> { |
95 : profile_(profile) {} | |
96 | |
97 SettingsFrontend::DefaultObserver::~DefaultObserver() {} | |
98 | |
99 void SettingsFrontend::DefaultObserver::OnSettingsChanged( | |
100 const std::string& extension_id, const std::string& changes_json) { | |
101 profile_->GetExtensionEventRouter()->DispatchEventToExtension( | |
102 extension_id, | |
103 extension_event_names::kOnSettingsChanged, | |
104 // This is the list of function arguments to pass to the onChanged | |
105 // handler of extensions, a single argument with the list of changes. | |
106 std::string("[") + changes_json + "]", | |
107 NULL, | |
108 GURL()); | |
109 } | |
110 | |
111 // Core | |
112 | |
113 class SettingsFrontend::Core | |
114 : public base::RefCountedThreadSafe<Core> { | |
115 public: | 83 public: |
116 explicit Core( | 84 // Creates a new BackendWrapper and initializes it on the FILE thread. |
117 // Ownership taken. | 85 static scoped_refptr<BackendWrapper> CreateAndInit( |
118 SettingsStorageFactory* storage_factory, | 86 const scoped_refptr<SettingsStorageFactory>& factory, |
119 const scoped_refptr<SettingsObserverList>& observers) | 87 const scoped_refptr<SettingsObserverList>& observers, |
120 : storage_factory_(storage_factory), | 88 const FilePath& path) { |
121 observers_(observers), | |
122 backends_(NULL) { | |
123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 90 scoped_refptr<BackendWrapper> backend_wrapper = |
| 91 new BackendWrapper(factory, observers); |
| 92 BrowserThread::PostTask( |
| 93 BrowserThread::FILE, |
| 94 FROM_HERE, |
| 95 base::Bind( |
| 96 &SettingsFrontend::BackendWrapper::InitOnFileThread, |
| 97 backend_wrapper, |
| 98 path)); |
| 99 return backend_wrapper; |
124 } | 100 } |
125 | 101 |
126 typedef base::Callback<void(Backends*)> BackendsCallback; | 102 typedef base::Callback<void(SettingsBackend*)> BackendCallback; |
127 | 103 |
128 // Does any FILE thread specific initialization, such as construction of | 104 // Runs |callback| with the wrapped Backend on the FILE thread. |
129 // |backend_|. Must be called before any call to | 105 void RunWithBackend(const BackendCallback& callback) { |
130 // RunWithBackendOnFileThread(). | |
131 void InitOnFileThread(const FilePath& profile_path) { | |
132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
133 DCHECK(!backends_); | |
134 backends_ = | |
135 new Backends( | |
136 storage_factory_.release(), profile_path, observers_); | |
137 } | |
138 | |
139 // Runs |callback| with both the extensions and apps settings on the FILE | |
140 // thread. | |
141 void RunWithBackends(const BackendsCallback& callback) { | |
142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
143 BrowserThread::PostTask( | 107 BrowserThread::PostTask( |
144 BrowserThread::FILE, | 108 BrowserThread::FILE, |
145 FROM_HERE, | 109 FROM_HERE, |
146 base::Bind( | 110 base::Bind( |
147 &SettingsFrontend::Core::RunWithBackendsOnFileThread, | 111 &SettingsFrontend::BackendWrapper::RunWithBackendOnFileThread, |
148 this, | 112 this, |
149 callback)); | 113 callback)); |
150 } | 114 } |
151 | 115 |
152 private: | 116 private: |
153 void RunWithBackendsOnFileThread(const BackendsCallback& callback) { | 117 friend class base::RefCountedThreadSafe<BackendWrapper>; |
154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 118 |
155 DCHECK(backends_); | 119 BackendWrapper( |
156 callback.Run(backends_); | 120 const scoped_refptr<SettingsStorageFactory>& storage_factory, |
| 121 const scoped_refptr<SettingsObserverList>& observers) |
| 122 : storage_factory_(storage_factory), |
| 123 observers_(observers), |
| 124 backend_(NULL) { |
| 125 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
157 } | 126 } |
158 | 127 |
159 virtual ~Core() { | 128 virtual ~BackendWrapper() { |
160 if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) { | 129 if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) { |
161 delete backends_; | 130 delete backend_; |
162 } else if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 131 } else if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
163 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, backends_); | 132 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, backend_); |
164 } else { | 133 } else { |
165 NOTREACHED(); | 134 NOTREACHED(); |
166 } | 135 } |
167 } | 136 } |
168 | 137 |
169 friend class base::RefCountedThreadSafe<Core>; | 138 void InitOnFileThread(const FilePath& path) { |
| 139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 140 DCHECK(!backend_); |
| 141 backend_ = new SettingsBackend(storage_factory_, path, observers_); |
| 142 storage_factory_ = NULL; |
| 143 observers_ = NULL; |
| 144 } |
170 | 145 |
171 // Leveldb storage area factory. Ownership passed to Backends on Init. | 146 void RunWithBackendOnFileThread(const BackendCallback& callback) { |
172 scoped_ptr<SettingsStorageFactory> storage_factory_; | 147 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 148 DCHECK(backend_); |
| 149 callback.Run(backend_); |
| 150 } |
173 | 151 |
174 // Observers to settings changes (thread safe). | 152 // Only need these until |backend_| exists. |
| 153 scoped_refptr<SettingsStorageFactory> storage_factory_; |
175 scoped_refptr<SettingsObserverList> observers_; | 154 scoped_refptr<SettingsObserverList> observers_; |
176 | 155 |
177 // Backends for extensions and apps settings. Lives on FILE thread. | 156 // Wrapped Backend. Used exclusively on the FILE thread, and is created on |
178 Backends* backends_; | 157 // the FILE thread in InitOnFileThread. |
| 158 SettingsBackend* backend_; |
179 | 159 |
180 DISALLOW_COPY_AND_ASSIGN(Core); | 160 DISALLOW_COPY_AND_ASSIGN(BackendWrapper); |
181 }; | 161 }; |
182 | 162 |
183 // SettingsFrontend | 163 // SettingsFrontend |
184 | 164 |
185 /* static */ | 165 /* static */ |
186 SettingsFrontend* SettingsFrontend::Create(Profile* profile) { | 166 SettingsFrontend* SettingsFrontend::Create(Profile* profile) { |
187 return new SettingsFrontend(new SettingsLeveldbStorage::Factory(), profile); | 167 return new SettingsFrontend(new SettingsLeveldbStorage::Factory(), profile); |
188 } | 168 } |
189 | 169 |
190 /* static */ | 170 /* static */ |
191 SettingsFrontend* SettingsFrontend::Create( | 171 SettingsFrontend* SettingsFrontend::Create( |
192 SettingsStorageFactory* storage_factory, Profile* profile) { | 172 const scoped_refptr<SettingsStorageFactory>& storage_factory, |
| 173 Profile* profile) { |
193 return new SettingsFrontend(storage_factory, profile); | 174 return new SettingsFrontend(storage_factory, profile); |
194 } | 175 } |
195 | 176 |
196 SettingsFrontend::SettingsFrontend( | 177 SettingsFrontend::SettingsFrontend( |
197 SettingsStorageFactory* storage_factory, Profile* profile) | 178 const scoped_refptr<SettingsStorageFactory>& factory, Profile* profile) |
198 : profile_(profile), | 179 : profile_(profile), |
199 observers_(new SettingsObserverList()), | 180 observers_(new SettingsObserverList()), |
200 default_observer_(profile), | 181 profile_observer_(new DefaultObserver(profile)) { |
201 core_(new SettingsFrontend::Core(storage_factory, observers_)) { | |
202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
203 DCHECK(!profile->IsOffTheRecord()); | 183 DCHECK(!profile->IsOffTheRecord()); |
204 | 184 |
205 observers_->AddObserver(&default_observer_); | 185 observers_->AddObserver(profile_observer_.get()); |
206 | 186 |
207 BrowserThread::PostTask( | 187 const FilePath& profile_path = profile->GetPath(); |
208 BrowserThread::FILE, | 188 backends_[settings_namespace::LOCAL].app = |
209 FROM_HERE, | 189 BackendWrapper::CreateAndInit( |
210 base::Bind( | 190 factory, |
211 &SettingsFrontend::Core::InitOnFileThread, | 191 observers_, |
212 core_.get(), | 192 profile_path.AppendASCII( |
213 profile->GetPath())); | 193 ExtensionService::kLocalAppSettingsDirectoryName)); |
| 194 backends_[settings_namespace::LOCAL].extension = |
| 195 BackendWrapper::CreateAndInit( |
| 196 factory, |
| 197 observers_, |
| 198 profile_path.AppendASCII( |
| 199 ExtensionService::kLocalExtensionSettingsDirectoryName)); |
| 200 backends_[settings_namespace::SYNC].app = |
| 201 BackendWrapper::CreateAndInit( |
| 202 factory, |
| 203 observers_, |
| 204 profile_path.AppendASCII( |
| 205 ExtensionService::kSyncAppSettingsDirectoryName)); |
| 206 backends_[settings_namespace::SYNC].extension = |
| 207 BackendWrapper::CreateAndInit( |
| 208 factory, |
| 209 observers_, |
| 210 profile_path.AppendASCII( |
| 211 ExtensionService::kSyncExtensionSettingsDirectoryName)); |
214 } | 212 } |
215 | 213 |
216 SettingsFrontend::~SettingsFrontend() { | 214 SettingsFrontend::~SettingsFrontend() { |
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
218 observers_->RemoveObserver(&default_observer_); | 216 observers_->RemoveObserver(profile_observer_.get()); |
219 } | 217 } |
220 | 218 |
221 void SettingsFrontend::RunWithSyncableService( | 219 void SettingsFrontend::RunWithSyncableService( |
222 syncable::ModelType model_type, const SyncableServiceCallback& callback) { | 220 syncable::ModelType model_type, const SyncableServiceCallback& callback) { |
223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 222 scoped_refptr<BackendWrapper> backend; |
224 switch (model_type) { | 223 switch (model_type) { |
| 224 case syncable::APP_SETTINGS: |
| 225 backend = backends_[settings_namespace::SYNC].app; |
| 226 break; |
| 227 |
225 case syncable::EXTENSION_SETTINGS: | 228 case syncable::EXTENSION_SETTINGS: |
226 core_->RunWithBackends( | 229 backend = backends_[settings_namespace::SYNC].extension; |
227 base::Bind(&CallbackWithExtensionsBackend, callback)); | |
228 break; | 230 break; |
229 case syncable::APP_SETTINGS: | 231 |
230 core_->RunWithBackends( | |
231 base::Bind(&CallbackWithAppsBackend, callback)); | |
232 break; | |
233 default: | 232 default: |
234 NOTREACHED(); | 233 NOTREACHED(); |
235 } | 234 } |
| 235 backend->RunWithBackend(base::Bind(&CallbackWithSyncableService, callback)); |
236 } | 236 } |
237 | 237 |
238 void SettingsFrontend::RunWithStorage( | 238 void SettingsFrontend::RunWithStorage( |
239 const std::string& extension_id, | 239 const std::string& extension_id, |
| 240 settings_namespace::Namespace settings_namespace, |
240 const StorageCallback& callback) { | 241 const StorageCallback& callback) { |
241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 242 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
242 | 243 |
243 const Extension* extension = | 244 const Extension* extension = |
244 profile_->GetExtensionService()->GetExtensionById(extension_id, true); | 245 profile_->GetExtensionService()->GetExtensionById(extension_id, true); |
245 if (!extension) { | 246 if (!extension) { |
246 BrowserThread::PostTask( | 247 BrowserThread::PostTask( |
247 BrowserThread::FILE, | 248 BrowserThread::FILE, |
248 FROM_HERE, | 249 FROM_HERE, |
249 base::Bind(&CallbackWithNullStorage, callback)); | 250 base::Bind(&CallbackWithNullStorage, callback)); |
250 return; | 251 return; |
251 } | 252 } |
252 | 253 |
| 254 scoped_refptr<BackendWrapper> backend; |
253 if (extension->is_app()) { | 255 if (extension->is_app()) { |
254 core_->RunWithBackends( | 256 backend = backends_[settings_namespace].app; |
255 base::Bind(&CallbackWithAppsStorage, extension_id, callback)); | |
256 } else { | 257 } else { |
257 core_->RunWithBackends( | 258 backend = backends_[settings_namespace].extension; |
258 base::Bind(&CallbackWithExtensionsStorage, extension_id, callback)); | |
259 } | 259 } |
| 260 backend->RunWithBackend( |
| 261 base::Bind(&CallbackWithStorage, extension_id, callback)); |
260 } | 262 } |
261 | 263 |
262 void SettingsFrontend::DeleteStorageSoon( | 264 void SettingsFrontend::DeleteStorageSoon( |
263 const std::string& extension_id) { | 265 const std::string& extension_id) { |
264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 266 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
265 core_->RunWithBackends(base::Bind(&DeleteStorageOnFileThread, extension_id)); | 267 SettingsFrontend::BackendWrapper::BackendCallback callback = |
| 268 base::Bind(&DeleteStorageOnFileThread, extension_id); |
| 269 for (std::map<settings_namespace::Namespace, BackendWrappers>::iterator it = |
| 270 backends_.begin(); it != backends_.end(); ++it) { |
| 271 it->second.app->RunWithBackend(callback); |
| 272 it->second.extension->RunWithBackend(callback); |
| 273 } |
266 } | 274 } |
267 | 275 |
268 scoped_refptr<SettingsObserverList> | 276 scoped_refptr<SettingsObserverList> SettingsFrontend::GetObservers() { |
269 SettingsFrontend::GetObservers() { | |
270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 277 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
271 return observers_; | 278 return observers_; |
272 } | 279 } |
273 | 280 |
| 281 // BackendWrappers |
| 282 |
| 283 SettingsFrontend::BackendWrappers::BackendWrappers() {} |
| 284 SettingsFrontend::BackendWrappers::~BackendWrappers() {} |
| 285 |
274 } // namespace extensions | 286 } // namespace extensions |
OLD | NEW |