Chromium Code Reviews| 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::NamespaceToString(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 |
|
not at google - send to devlin
2011/11/23 02:24:43
This is basically what used to be Core, and replac
| |
| 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. |
| 178 Backends* backends_; | 157 SettingsBackend* backend_; |
|
Matt Perry
2011/11/23 03:35:05
add a comment to point out the ownership and threa
not at google - send to devlin
2011/11/23 11:04:52
Done.
| |
| 179 | 158 |
| 180 DISALLOW_COPY_AND_ASSIGN(Core); | 159 DISALLOW_COPY_AND_ASSIGN(BackendWrapper); |
| 181 }; | 160 }; |
| 182 | 161 |
| 183 // SettingsFrontend | 162 // SettingsFrontend |
| 184 | 163 |
| 185 /* static */ | 164 /* static */ |
| 186 SettingsFrontend* SettingsFrontend::Create(Profile* profile) { | 165 SettingsFrontend* SettingsFrontend::Create(Profile* profile) { |
| 187 return new SettingsFrontend(new SettingsLeveldbStorage::Factory(), profile); | 166 return new SettingsFrontend(new SettingsLeveldbStorage::Factory(), profile); |
| 188 } | 167 } |
| 189 | 168 |
| 190 /* static */ | 169 /* static */ |
| 191 SettingsFrontend* SettingsFrontend::Create( | 170 SettingsFrontend* SettingsFrontend::Create( |
| 192 SettingsStorageFactory* storage_factory, Profile* profile) { | 171 const scoped_refptr<SettingsStorageFactory>& storage_factory, |
| 172 Profile* profile) { | |
| 193 return new SettingsFrontend(storage_factory, profile); | 173 return new SettingsFrontend(storage_factory, profile); |
| 194 } | 174 } |
| 195 | 175 |
| 196 SettingsFrontend::SettingsFrontend( | 176 SettingsFrontend::SettingsFrontend( |
| 197 SettingsStorageFactory* storage_factory, Profile* profile) | 177 const scoped_refptr<SettingsStorageFactory>& factory, Profile* profile) |
| 198 : profile_(profile), | 178 : profile_(profile), |
| 199 observers_(new SettingsObserverList()), | 179 observers_(new SettingsObserverList()), |
| 200 default_observer_(profile), | 180 profile_observer_(new DefaultObserver(profile)) { |
| 201 core_(new SettingsFrontend::Core(storage_factory, observers_)) { | |
| 202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 203 DCHECK(!profile->IsOffTheRecord()); | 182 DCHECK(!profile->IsOffTheRecord()); |
| 204 | 183 |
| 205 observers_->AddObserver(&default_observer_); | 184 observers_->AddObserver(profile_observer_.get()); |
| 206 | 185 |
| 207 BrowserThread::PostTask( | 186 const FilePath& profile_path = profile->GetPath(); |
| 208 BrowserThread::FILE, | 187 backends_[settings_namespace::LOCAL][true] = |
| 209 FROM_HERE, | 188 BackendWrapper::CreateAndInit( |
| 210 base::Bind( | 189 factory, |
|
not at google - send to devlin
2011/11/23 02:24:43
This (and the other 3 occurrences) is basically wh
Matt Perry
2011/11/23 03:35:05
This seems fine to me. If you really hate it, here
not at google - send to devlin
2011/11/23 11:04:52
Yeah, not so keen on that because of the 3 interde
| |
| 211 &SettingsFrontend::Core::InitOnFileThread, | 190 observers_, |
| 212 core_.get(), | 191 profile_path.AppendASCII( |
| 213 profile->GetPath())); | 192 ExtensionService::kLocalAppSettingsDirectoryName)); |
| 193 backends_[settings_namespace::LOCAL][false] = | |
| 194 BackendWrapper::CreateAndInit( | |
| 195 factory, | |
| 196 observers_, | |
| 197 profile_path.AppendASCII( | |
| 198 ExtensionService::kLocalExtensionSettingsDirectoryName)); | |
| 199 backends_[settings_namespace::SYNC][true] = | |
| 200 BackendWrapper::CreateAndInit( | |
| 201 factory, | |
| 202 observers_, | |
| 203 profile_path.AppendASCII( | |
| 204 ExtensionService::kSyncAppSettingsDirectoryName)); | |
| 205 backends_[settings_namespace::SYNC][false] = | |
| 206 BackendWrapper::CreateAndInit( | |
| 207 factory, | |
| 208 observers_, | |
| 209 profile_path.AppendASCII( | |
| 210 ExtensionService::kSyncExtensionSettingsDirectoryName)); | |
|
not at google - send to devlin
2011/11/23 02:24:43
except this is kinda yuck
| |
| 214 } | 211 } |
| 215 | 212 |
| 216 SettingsFrontend::~SettingsFrontend() { | 213 SettingsFrontend::~SettingsFrontend() { |
| 217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 214 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 218 observers_->RemoveObserver(&default_observer_); | 215 observers_->RemoveObserver(profile_observer_.get()); |
| 219 } | 216 } |
| 220 | 217 |
| 221 void SettingsFrontend::RunWithSyncableService( | 218 void SettingsFrontend::RunWithSyncableService( |
| 222 syncable::ModelType model_type, const SyncableServiceCallback& callback) { | 219 syncable::ModelType model_type, const SyncableServiceCallback& callback) { |
| 223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 224 switch (model_type) { | 221 DCHECK(model_type == syncable::APP_SETTINGS || |
| 225 case syncable::EXTENSION_SETTINGS: | 222 model_type == syncable::EXTENSION_SETTINGS); |
| 226 core_->RunWithBackends( | 223 bool is_app = model_type == syncable::APP_SETTINGS; |
| 227 base::Bind(&CallbackWithExtensionsBackend, callback)); | 224 backends_[settings_namespace::SYNC][is_app]->RunWithBackend( |
| 228 break; | 225 base::Bind(&CallbackWithSyncableService, callback)); |
| 229 case syncable::APP_SETTINGS: | |
| 230 core_->RunWithBackends( | |
| 231 base::Bind(&CallbackWithAppsBackend, callback)); | |
| 232 break; | |
| 233 default: | |
| 234 NOTREACHED(); | |
| 235 } | |
| 236 } | 226 } |
| 237 | 227 |
| 238 void SettingsFrontend::RunWithStorage( | 228 void SettingsFrontend::RunWithStorage( |
| 239 const std::string& extension_id, | 229 const std::string& extension_id, |
| 230 settings_namespace::Namespace settings_namespace, | |
| 240 const StorageCallback& callback) { | 231 const StorageCallback& callback) { |
| 241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 242 | 233 |
| 243 const Extension* extension = | 234 const Extension* extension = |
| 244 profile_->GetExtensionService()->GetExtensionById(extension_id, true); | 235 profile_->GetExtensionService()->GetExtensionById(extension_id, true); |
| 245 if (!extension) { | 236 if (!extension) { |
| 246 BrowserThread::PostTask( | 237 BrowserThread::PostTask( |
| 247 BrowserThread::FILE, | 238 BrowserThread::FILE, |
| 248 FROM_HERE, | 239 FROM_HERE, |
| 249 base::Bind(&CallbackWithNullStorage, callback)); | 240 base::Bind(&CallbackWithNullStorage, callback)); |
| 250 return; | 241 return; |
| 251 } | 242 } |
| 252 | 243 |
| 253 if (extension->is_app()) { | 244 backends_[settings_namespace][extension->is_app()]->RunWithBackend( |
| 254 core_->RunWithBackends( | 245 base::Bind(&CallbackWithStorage, extension_id, callback)); |
| 255 base::Bind(&CallbackWithAppsStorage, extension_id, callback)); | |
| 256 } else { | |
| 257 core_->RunWithBackends( | |
| 258 base::Bind(&CallbackWithExtensionsStorage, extension_id, callback)); | |
| 259 } | |
| 260 } | 246 } |
| 261 | 247 |
| 262 void SettingsFrontend::DeleteStorageSoon( | 248 void SettingsFrontend::DeleteStorageSoon( |
| 263 const std::string& extension_id) { | 249 const std::string& extension_id) { |
| 264 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 265 core_->RunWithBackends(base::Bind(&DeleteStorageOnFileThread, extension_id)); | 251 SettingsFrontend::BackendWrapper::BackendCallback callback = |
| 252 base::Bind(&DeleteStorageOnFileThread, extension_id); | |
| 253 backends_[settings_namespace::LOCAL][true]->RunWithBackend(callback); | |
| 254 backends_[settings_namespace::LOCAL][false]->RunWithBackend(callback); | |
| 255 backends_[settings_namespace::SYNC][true]->RunWithBackend(callback); | |
| 256 backends_[settings_namespace::SYNC][false]->RunWithBackend(callback); | |
|
not at google - send to devlin
2011/11/23 02:24:43
as is this
Matt Perry
2011/11/23 03:35:05
again, seems ok (and better than the alternatives)
not at google - send to devlin
2011/11/23 11:04:52
iterator'd
| |
| 266 } | 257 } |
| 267 | 258 |
| 268 scoped_refptr<SettingsObserverList> | 259 scoped_refptr<SettingsObserverList> SettingsFrontend::GetObservers() { |
| 269 SettingsFrontend::GetObservers() { | |
| 270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 271 return observers_; | 261 return observers_; |
| 272 } | 262 } |
| 273 | 263 |
| 274 } // namespace extensions | 264 } // namespace extensions |
| OLD | NEW |