diff options
author | joaodasilva@chromium.org <joaodasilva@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-19 17:22:39 +0000 |
---|---|---|
committer | joaodasilva@chromium.org <joaodasilva@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-19 17:22:39 +0000 |
commit | 060d49788f6812ae1a6e82d7759699cc4538a3c3 (patch) | |
tree | 1f00dacedf9bc39f38ef0671810354f07dcccef8 | |
parent | 2e695a8e4cfcc006d0d02323c8c1115b98eb2faa (diff) | |
download | chromium_src-060d49788f6812ae1a6e82d7759699cc4538a3c3.zip chromium_src-060d49788f6812ae1a6e82d7759699cc4538a3c3.tar.gz chromium_src-060d49788f6812ae1a6e82d7759699cc4538a3c3.tar.bz2 |
Refactored SettingsFrontend and forwarding of calls to the backends.
Added a SettingsNamespaceFrontend interface for namespace frontends, that allows different namespaces to forward StorageCallbacks in their own way.
The LOCAL and SYNC namespaces use an implementation that does the same as before, but the new MANAGED namespace can now be implemented using a ValueStore that loads settings from policies, in the UI thread.
BUG=108992
TEST=Everything works as before, all tests are green
Review URL: https://chromiumcodereview.appspot.com/10784035
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@147464 0039d316-1c4b-4281-b951-d872f2087c98
20 files changed, 447 insertions, 268 deletions
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index 2eff617..b3fb259 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc @@ -1804,7 +1804,7 @@ void ExtensionService::UnloadExtension( // Clean up runtime data. extension_runtime_data_.erase(extension_id); -if (disabled_extensions_.Contains(extension->id())) { + if (disabled_extensions_.Contains(extension->id())) { UnloadedExtensionInfo details(extension, reason); details.already_disabled = true; disabled_extensions_.Remove(extension->id()); @@ -1819,7 +1819,7 @@ if (disabled_extensions_.Contains(extension->id())) { return; } -// Remove the extension from our list. + // Remove the extension from our list. extensions_.Remove(extension->id()); NotifyExtensionUnloaded(extension.get(), reason); diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc index 71e4ba1..7827490 100644 --- a/chrome/browser/extensions/extension_service_unittest.cc +++ b/chrome/browser/extensions/extension_service_unittest.cc @@ -4138,6 +4138,8 @@ TEST(ExtensionServiceTestSimple, Enabledness) { // Explicitly delete all the resources used in this test. profile.reset(); service = NULL; + // Execute any pending deletion tasks. + loop.RunAllPending(); } // Test loading extensions that require limited and unlimited storage quotas. diff --git a/chrome/browser/extensions/extension_ui_unittest.cc b/chrome/browser/extensions/extension_ui_unittest.cc index 465fe45..03bb89a 100644 --- a/chrome/browser/extensions/extension_ui_unittest.cc +++ b/chrome/browser/extensions/extension_ui_unittest.cc @@ -21,16 +21,18 @@ using extensions::Extension; class ExtensionUITest : public testing::Test { public: - ExtensionUITest() : ui_thread_(content::BrowserThread::UI, &message_loop_) { - } + ExtensionUITest() + : ui_thread_(content::BrowserThread::UI, &message_loop_), + file_thread_(content::BrowserThread::FILE, &message_loop_) {} protected: - void SetUp() { + virtual void SetUp() OVERRIDE { // Create an ExtensionService and ManagementPolicy to inject into the // ExtensionSettingsHandler. + profile_.reset(new TestingProfile()); extensions::TestExtensionSystem* system = static_cast<extensions::TestExtensionSystem*>( - extensions::ExtensionSystem::Get(&profile_)); + extensions::ExtensionSystem::Get(profile_.get())); extension_service_ = system->CreateExtensionService( CommandLine::ForCurrentProcess(), FilePath(), false); management_policy_ = system->CreateManagementPolicy(); @@ -39,6 +41,13 @@ class ExtensionUITest : public testing::Test { management_policy_)); } + virtual void TearDown() OVERRIDE { + handler_.reset(); + profile_.reset(); + // Execute any pending deletion tasks. + message_loop_.RunAllPending(); + } + static DictionaryValue* DeserializeJSONTestData(const FilePath& path, std::string *error) { Value* value; @@ -110,7 +119,8 @@ class ExtensionUITest : public testing::Test { MessageLoop message_loop_; content::TestBrowserThread ui_thread_; - TestingProfile profile_; + content::TestBrowserThread file_thread_; + scoped_ptr<TestingProfile> profile_; ExtensionService* extension_service_; extensions::ManagementPolicy* management_policy_; scoped_ptr<ExtensionSettingsHandler> handler_; diff --git a/chrome/browser/extensions/page_action_controller_unittest.cc b/chrome/browser/extensions/page_action_controller_unittest.cc index 13a0b95..924f93f 100644 --- a/chrome/browser/extensions/page_action_controller_unittest.cc +++ b/chrome/browser/extensions/page_action_controller_unittest.cc @@ -27,10 +27,10 @@ namespace { class PageActionControllerTest : public TabContentsTestHarness { public: PageActionControllerTest() - : ui_thread_(BrowserThread::UI, MessageLoop::current()) { - } + : ui_thread_(BrowserThread::UI, MessageLoop::current()), + file_thread_(BrowserThread::FILE, MessageLoop::current()) {} - virtual void SetUp() { + virtual void SetUp() OVERRIDE { TabContentsTestHarness::SetUp(); // Create an ExtensionService so the PageActionController can find its // extensions. @@ -51,6 +51,7 @@ class PageActionControllerTest : public TabContentsTestHarness { private: content::TestBrowserThread ui_thread_; + content::TestBrowserThread file_thread_; }; TEST_F(PageActionControllerTest, NavigationClearsState) { diff --git a/chrome/browser/extensions/script_badge_controller_unittest.cc b/chrome/browser/extensions/script_badge_controller_unittest.cc index cf5a8b0..8b0623b 100644 --- a/chrome/browser/extensions/script_badge_controller_unittest.cc +++ b/chrome/browser/extensions/script_badge_controller_unittest.cc @@ -35,8 +35,8 @@ namespace { class ScriptBadgeControllerTest : public TabContentsTestHarness { public: ScriptBadgeControllerTest() - : ui_thread_(BrowserThread::UI, MessageLoop::current()) { - } + : ui_thread_(BrowserThread::UI, MessageLoop::current()), + file_thread_(BrowserThread::FILE, MessageLoop::current()) {} virtual void SetUp() OVERRIDE { // Note that this sets a PageActionController into the @@ -82,6 +82,7 @@ class ScriptBadgeControllerTest : public TabContentsTestHarness { private: content::TestBrowserThread ui_thread_; + content::TestBrowserThread file_thread_; }; struct CountingNotificationObserver : public content::NotificationObserver { diff --git a/chrome/browser/extensions/settings/managed_value_store_cache.cc b/chrome/browser/extensions/settings/managed_value_store_cache.cc new file mode 100644 index 0000000..7e24191 --- /dev/null +++ b/chrome/browser/extensions/settings/managed_value_store_cache.cc @@ -0,0 +1,43 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/settings/managed_value_store_cache.h" + +#include "base/logging.h" +#include "base/message_loop_proxy.h" +#include "base/sequenced_task_runner.h" +#include "chrome/common/extensions/extension.h" +#include "content/public/browser/browser_thread.h" + +using content::BrowserThread; + +namespace extensions { + +ManagedValueStoreCache::ManagedValueStoreCache( + policy::PolicyService* policy_service) {} + +ManagedValueStoreCache::~ManagedValueStoreCache() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +} + +scoped_refptr<base::MessageLoopProxy> + ManagedValueStoreCache::GetMessageLoop() const { + return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI); +} + +void ManagedValueStoreCache::RunWithValueStoreForExtension( + const StorageCallback& callback, + scoped_refptr<const Extension> extension) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + NOTREACHED() << "Not implemented yet."; + callback.Run(NULL); +} + +void ManagedValueStoreCache::DeleteStorageSoon( + const std::string& extension_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + // Not implemented yet. +} + +} // namespace extensions diff --git a/chrome/browser/extensions/settings/managed_value_store_cache.h b/chrome/browser/extensions/settings/managed_value_store_cache.h new file mode 100644 index 0000000..f262009 --- /dev/null +++ b/chrome/browser/extensions/settings/managed_value_store_cache.h @@ -0,0 +1,40 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_SETTINGS_MANAGED_VALUE_STORE_CACHE_H_ +#define CHROME_BROWSER_EXTENSIONS_SETTINGS_MANAGED_VALUE_STORE_CACHE_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "chrome/browser/extensions/settings/value_store_cache.h" + +namespace policy { +class PolicyService; +} // namespace policy + +namespace extensions { + +// TODO(joaodasilva): this is a work in progress. http://crbug.com/108992 +class ManagedValueStoreCache : public ValueStoreCache { + public: + explicit ManagedValueStoreCache(policy::PolicyService* policy_service); + virtual ~ManagedValueStoreCache(); + + // ValueStoreCache implementation: + + virtual scoped_refptr<base::MessageLoopProxy> GetMessageLoop() const OVERRIDE; + + virtual void RunWithValueStoreForExtension( + const StorageCallback& callback, + scoped_refptr<const Extension> extension) OVERRIDE; + + virtual void DeleteStorageSoon(const std::string& extension_id) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(ManagedValueStoreCache); +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_SETTINGS_MANAGED_VALUE_STORE_CACHE_H_ diff --git a/chrome/browser/extensions/settings/settings_api.cc b/chrome/browser/extensions/settings/settings_api.cc index bcb05dc..56ccfbd 100644 --- a/chrome/browser/extensions/settings/settings_api.cc +++ b/chrome/browser/extensions/settings/settings_api.cc @@ -4,11 +4,13 @@ #include "chrome/browser/extensions/settings/settings_api.h" +#include <string> +#include <vector> + #include "base/bind.h" #include "base/values.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extensions_quota_service.h" -#include "chrome/browser/extensions/settings/settings_api.h" #include "chrome/browser/extensions/settings/settings_frontend.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/api/storage.h" @@ -19,7 +21,7 @@ namespace extensions { using content::BrowserThread; namespace { -const char* kUnsupportedArgumentType = "Unsupported argument type"; +const char kUnsupportedArgumentType[] = "Unsupported argument type"; } // namespace // SettingsFunction @@ -58,12 +60,11 @@ bool SettingsFunction::RunImpl() { frontend->RunWithStorage( extension_id(), settings_namespace_, - base::Bind(&SettingsFunction::RunWithStorageOnFileThread, this)); + base::Bind(&SettingsFunction::AsyncRunWithStorage, this)); return true; } -void SettingsFunction::RunWithStorageOnFileThread(ValueStore* storage) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); +void SettingsFunction::AsyncRunWithStorage(ValueStore* storage) { bool success = RunWithStorage(storage); BrowserThread::PostTask( BrowserThread::UI, @@ -72,7 +73,6 @@ void SettingsFunction::RunWithStorageOnFileThread(ValueStore* storage) { } bool SettingsFunction::UseReadResult(ValueStore::ReadResult result) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); if (result->HasError()) { error_ = result->error(); return false; @@ -83,7 +83,6 @@ bool SettingsFunction::UseReadResult(ValueStore::ReadResult result) { } bool SettingsFunction::UseWriteResult(ValueStore::WriteResult result) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); if (result->HasError()) { error_ = result->error(); return false; @@ -126,8 +125,7 @@ std::vector<std::string> GetKeys(const DictionaryValue& dict) { } // Creates quota heuristics for settings modification. -static void GetModificationQuotaLimitHeuristics( - QuotaLimitHeuristics* heuristics) { +void GetModificationQuotaLimitHeuristics(QuotaLimitHeuristics* heuristics) { QuotaLimitHeuristic::Config longLimitConfig = { // See storage.json for current value. api::storage::sync::MAX_WRITE_OPERATIONS_PER_HOUR, @@ -153,7 +151,6 @@ static void GetModificationQuotaLimitHeuristics( } // namespace bool GetSettingsFunction::RunWithStorage(ValueStore* storage) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); Value* input = NULL; EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input)); @@ -193,7 +190,6 @@ bool GetSettingsFunction::RunWithStorage(ValueStore* storage) { } bool GetBytesInUseSettingsFunction::RunWithStorage(ValueStore* storage) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); Value* input = NULL; EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input)); @@ -228,7 +224,6 @@ bool GetBytesInUseSettingsFunction::RunWithStorage(ValueStore* storage) { } bool SetSettingsFunction::RunWithStorage(ValueStore* storage) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); DictionaryValue* input = NULL; EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &input)); return UseWriteResult(storage->Set(ValueStore::DEFAULTS, *input)); @@ -240,7 +235,6 @@ void SetSettingsFunction::GetQuotaLimitHeuristics( } bool RemoveSettingsFunction::RunWithStorage(ValueStore* storage) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); Value* input = NULL; EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input)); @@ -269,7 +263,6 @@ void RemoveSettingsFunction::GetQuotaLimitHeuristics( } bool ClearSettingsFunction::RunWithStorage(ValueStore* storage) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); return UseWriteResult(storage->Clear()); } diff --git a/chrome/browser/extensions/settings/settings_api.h b/chrome/browser/extensions/settings/settings_api.h index db96d3d..c4d0fd5 100644 --- a/chrome/browser/extensions/settings/settings_api.h +++ b/chrome/browser/extensions/settings/settings_api.h @@ -8,8 +8,8 @@ #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" #include "chrome/browser/extensions/extension_function.h" -#include "chrome/browser/extensions/settings/settings_backend.h" #include "chrome/browser/extensions/settings/settings_namespace.h" +#include "chrome/browser/extensions/settings/settings_observer.h" #include "chrome/browser/value_store/value_store.h" namespace extensions { @@ -30,8 +30,7 @@ class SettingsFunction : public AsyncExtensionFunction { virtual bool RunImpl() OVERRIDE; // Extension settings function implementations should do their work here. - // This runs on the FILE thread. - // + // The SettingsFrontend makes sure this is posted to the appropriate thread. // Implementations should fill in args themselves, though (like RunImpl) // may return false to imply failure. virtual bool RunWithStorage(ValueStore* storage) = 0; @@ -48,7 +47,7 @@ class SettingsFunction : public AsyncExtensionFunction { private: // Called via PostTask from RunImpl. Calls RunWithStorage and then // SendReponse with its success value. - void RunWithStorageOnFileThread(ValueStore* storage); + void AsyncRunWithStorage(ValueStore* storage); // The settings namespace the call was for. For example, SYNC if the API // call was chrome.settings.experimental.sync..., LOCAL if .local, etc. diff --git a/chrome/browser/extensions/settings/settings_frontend.cc b/chrome/browser/extensions/settings/settings_frontend.cc index 7eef6bc..bdf0fe5 100644 --- a/chrome/browser/extensions/settings/settings_frontend.cc +++ b/chrome/browser/extensions/settings/settings_frontend.cc @@ -4,21 +4,21 @@ #include "chrome/browser/extensions/settings/settings_frontend.h" +#include <limits> + #include "base/bind.h" +#include "base/bind_helpers.h" #include "base/file_path.h" -#include "base/string_number_conversions.h" #include "chrome/browser/extensions/extension_event_names.h" #include "chrome/browser/extensions/extension_event_router.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/settings/leveldb_settings_storage_factory.h" +#include "chrome/browser/extensions/settings/managed_value_store_cache.h" #include "chrome/browser/extensions/settings/settings_backend.h" -#include "chrome/browser/extensions/settings/settings_namespace.h" -#include "chrome/browser/extensions/settings/weak_unlimited_settings_storage.h" +#include "chrome/browser/extensions/settings/sync_or_local_value_store_cache.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/value_store/leveldb_value_store.h" #include "chrome/common/extensions/api/storage.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/notification_service.h" using content::BrowserThread; @@ -52,43 +52,6 @@ class DefaultObserver : public SettingsObserver { Profile* const profile_; }; -void CallbackWithSyncableService( - const SettingsFrontend::SyncableServiceCallback& callback, - SettingsBackend* backend) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - callback.Run(backend); -} - -void CallbackWithStorage( - const std::string& extension_id, - const SettingsFrontend::StorageCallback& callback, - SettingsBackend* backend) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - callback.Run(backend->GetStorage(extension_id)); -} - -void CallbackWithNullStorage( - const SettingsFrontend::StorageCallback& callback) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - callback.Run(NULL); -} - -void DeleteStorageOnFileThread( - const std::string& extension_id, SettingsBackend* backend) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - backend->DeleteStorage(extension_id); -} - -void CallbackWithUnlimitedStorage( - const std::string& extension_id, - const SettingsFrontend::StorageCallback& callback, - SettingsBackend* backend) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - WeakUnlimitedSettingsStorage unlimited_storage( - backend->GetStorage(extension_id)); - callback.Run(&unlimited_storage); -} - SettingsStorageQuotaEnforcer::Limits GetLocalLimits() { SettingsStorageQuotaEnforcer::Limits limits = { static_cast<size_t>(api::storage::local::QUOTA_BYTES), @@ -109,100 +72,6 @@ SettingsStorageQuotaEnforcer::Limits GetSyncLimits() { } // namespace -// Ref-counted container for a SettingsBackend object. -class SettingsFrontend::BackendWrapper - : public base::RefCountedThreadSafe<BackendWrapper> { - public: - // Creates a new BackendWrapper and initializes it on the FILE thread. - static scoped_refptr<BackendWrapper> CreateAndInit( - const scoped_refptr<SettingsStorageFactory>& factory, - const SettingsStorageQuotaEnforcer::Limits& quota, - const scoped_refptr<SettingsObserverList>& observers, - const FilePath& path) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - scoped_refptr<BackendWrapper> backend_wrapper = - new BackendWrapper(factory, quota, observers); - BrowserThread::PostTask( - BrowserThread::FILE, - FROM_HERE, - base::Bind( - &SettingsFrontend::BackendWrapper::InitOnFileThread, - backend_wrapper, - path)); - return backend_wrapper; - } - - typedef base::Callback<void(SettingsBackend*)> BackendCallback; - - // Runs |callback| with the wrapped Backend on the FILE thread. - void RunWithBackend(const BackendCallback& callback) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - BrowserThread::PostTask( - BrowserThread::FILE, - FROM_HERE, - base::Bind( - &SettingsFrontend::BackendWrapper::RunWithBackendOnFileThread, - this, - callback)); - } - - SettingsBackend* GetBackend() const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - return backend_; - } - - private: - friend class base::RefCountedThreadSafe<BackendWrapper>; - - BackendWrapper( - const scoped_refptr<SettingsStorageFactory>& storage_factory, - const SettingsStorageQuotaEnforcer::Limits& quota, - const scoped_refptr<SettingsObserverList>& observers) - : storage_factory_(storage_factory), - quota_(quota), - observers_(observers), - backend_(NULL) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - } - - virtual ~BackendWrapper() { - if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) { - delete backend_; - } else if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { - BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, backend_); - } else { - NOTREACHED(); - } - } - - void InitOnFileThread(const FilePath& path) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - DCHECK(!backend_); - backend_ = new SettingsBackend(storage_factory_, path, quota_, observers_); - storage_factory_ = NULL; - observers_ = NULL; - } - - void RunWithBackendOnFileThread(const BackendCallback& callback) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - DCHECK(backend_); - callback.Run(backend_); - } - - // Only need these until |backend_| exists. - scoped_refptr<SettingsStorageFactory> storage_factory_; - const SettingsStorageQuotaEnforcer::Limits quota_; - scoped_refptr<SettingsObserverList> observers_; - - // Wrapped Backend. Used exclusively on the FILE thread, and is created on - // the FILE thread in InitOnFileThread. - SettingsBackend* backend_; - - DISALLOW_COPY_AND_ASSIGN(BackendWrapper); -}; - -// SettingsFrontend - // static SettingsFrontend* SettingsFrontend::Create(Profile* profile) { return new SettingsFrontend(new LeveldbSettingsStorageFactory(), profile); @@ -228,52 +97,47 @@ SettingsFrontend::SettingsFrontend( observers_->AddObserver(profile_observer_.get()); const FilePath& profile_path = profile->GetPath(); - backends_[settings_namespace::LOCAL].app = - BackendWrapper::CreateAndInit( + caches_[settings_namespace::LOCAL] = + new SyncOrLocalValueStoreCache( + settings_namespace::LOCAL, factory, local_quota_limit_, observers_, - profile_path.AppendASCII( - ExtensionService::kLocalAppSettingsDirectoryName)); - backends_[settings_namespace::LOCAL].extension = - BackendWrapper::CreateAndInit( - factory, - local_quota_limit_, - observers_, - profile_path.AppendASCII( - ExtensionService::kLocalExtensionSettingsDirectoryName)); - backends_[settings_namespace::SYNC].app = - BackendWrapper::CreateAndInit( + profile_path); + caches_[settings_namespace::SYNC] = + new SyncOrLocalValueStoreCache( + settings_namespace::SYNC, factory, sync_quota_limit_, observers_, - profile_path.AppendASCII( - ExtensionService::kSyncAppSettingsDirectoryName)); - backends_[settings_namespace::SYNC].extension = - BackendWrapper::CreateAndInit( - factory, - sync_quota_limit_, - observers_, - profile_path.AppendASCII( - ExtensionService::kSyncExtensionSettingsDirectoryName)); + profile_path); + caches_[settings_namespace::MANAGED] = + new ManagedValueStoreCache(profile->GetPolicyService()); } SettingsFrontend::~SettingsFrontend() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); observers_->RemoveObserver(profile_observer_.get()); + // Destroy each cache in its preferred thread. The delete task will execute + // after any other task that might've been posted before. + for (CacheMap::iterator it = caches_.begin(); it != caches_.end(); ++it) { + ValueStoreCache* cache = it->second; + cache->GetMessageLoop()->DeleteSoon(FROM_HERE, cache); + } } syncer::SyncableService* SettingsFrontend::GetBackendForSync( syncer::ModelType type) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - std::map<settings_namespace::Namespace, BackendWrappers>::const_iterator - sync_backends = backends_.find(settings_namespace::SYNC); - DCHECK(sync_backends != backends_.end()); + CacheMap::const_iterator it = caches_.find(settings_namespace::SYNC); + DCHECK(it != caches_.end()); + const SyncOrLocalValueStoreCache* sync_cache = + static_cast<const SyncOrLocalValueStoreCache*>(it->second); switch (type) { case syncer::APP_SETTINGS: - return sync_backends->second.app->GetBackend(); + return sync_cache->GetAppBackend(); case syncer::EXTENSION_SETTINGS: - return sync_backends->second.extension->GetBackend(); + return sync_cache->GetExtensionBackend(); default: NOTREACHED(); return NULL; @@ -283,52 +147,37 @@ syncer::SyncableService* SettingsFrontend::GetBackendForSync( void SettingsFrontend::RunWithStorage( const std::string& extension_id, settings_namespace::Namespace settings_namespace, - const StorageCallback& callback) { + const ValueStoreCache::StorageCallback& callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - const Extension* extension = + ValueStoreCache* cache = caches_[settings_namespace]; + CHECK(cache); + + scoped_refptr<const Extension> extension = profile_->GetExtensionService()->GetExtensionById(extension_id, true); if (!extension) { - BrowserThread::PostTask( - BrowserThread::FILE, + cache->GetMessageLoop()->PostTask( FROM_HERE, - base::Bind(&CallbackWithNullStorage, callback)); + base::Bind(callback, static_cast<ValueStore*>(NULL))); return; } - // A neat way to implement unlimited storage; if the extension has the - // unlimited storage permission, force through all calls to Set() (in the - // same way that writes from sync ignore quota). - // But only if it's local storage (bad stuff would happen if sync'ed - // storage is allowed to be unlimited). - bool is_unlimited = - settings_namespace == settings_namespace::LOCAL && - extension->HasAPIPermission(APIPermission::kUnlimitedStorage); - - scoped_refptr<BackendWrapper> backend; - if (extension->is_app()) { - backend = backends_[settings_namespace].app; - } else { - backend = backends_[settings_namespace].extension; - } - - backend->RunWithBackend( - base::Bind( - is_unlimited ? - &CallbackWithUnlimitedStorage : &CallbackWithStorage, - extension_id, - callback)); + cache->GetMessageLoop()->PostTask( + FROM_HERE, + base::Bind(&ValueStoreCache::RunWithValueStoreForExtension, + base::Unretained(cache), callback, extension)); } void SettingsFrontend::DeleteStorageSoon( const std::string& extension_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - SettingsFrontend::BackendWrapper::BackendCallback callback = - base::Bind(&DeleteStorageOnFileThread, extension_id); - for (std::map<settings_namespace::Namespace, BackendWrappers>::iterator it = - backends_.begin(); it != backends_.end(); ++it) { - it->second.app->RunWithBackend(callback); - it->second.extension->RunWithBackend(callback); + for (CacheMap::iterator it = caches_.begin(); it != caches_.end(); ++it) { + ValueStoreCache* cache = it->second; + cache->GetMessageLoop()->PostTask( + FROM_HERE, + base::Bind(&ValueStoreCache::DeleteStorageSoon, + base::Unretained(cache), + extension_id)); } } @@ -337,9 +186,4 @@ scoped_refptr<SettingsObserverList> SettingsFrontend::GetObservers() { return observers_; } -// BackendWrappers - -SettingsFrontend::BackendWrappers::BackendWrappers() {} -SettingsFrontend::BackendWrappers::~BackendWrappers() {} - } // namespace extensions diff --git a/chrome/browser/extensions/settings/settings_frontend.h b/chrome/browser/extensions/settings/settings_frontend.h index c385fd3..f26c52d 100644 --- a/chrome/browser/extensions/settings/settings_frontend.h +++ b/chrome/browser/extensions/settings/settings_frontend.h @@ -5,10 +5,10 @@ #ifndef CHROME_BROWSER_EXTENSIONS_SETTINGS_SETTINGS_FRONTEND_H_ #define CHROME_BROWSER_EXTENSIONS_SETTINGS_SETTINGS_FRONTEND_H_ +#include <map> #include <string> #include "base/callback.h" -#include "base/compiler_specific.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/observer_list_threadsafe.h" @@ -16,7 +16,7 @@ #include "chrome/browser/extensions/settings/settings_observer.h" #include "chrome/browser/extensions/settings/settings_storage_factory.h" #include "chrome/browser/extensions/settings/settings_storage_quota_enforcer.h" -#include "chrome/browser/value_store/leveldb_value_store.h" +#include "chrome/browser/extensions/settings/value_store_cache.h" #include "sync/api/syncable_service.h" class Profile; @@ -30,44 +30,39 @@ namespace extensions { // GetBackendForSync(), which must be called on the FILE thread. class SettingsFrontend { public: - // Creates with the default factory. Ownership of |profile| not taken. + // Creates with the default factory. static SettingsFrontend* Create(Profile* profile); // Creates with a specific factory |storage_factory| (presumably for tests). - // Ownership of |profile| not taken. static SettingsFrontend* Create( const scoped_refptr<SettingsStorageFactory>& storage_factory, - // Owership NOT taken. Profile* profile); virtual ~SettingsFrontend(); - typedef base::Callback<void(syncer::SyncableService*)> - SyncableServiceCallback; - typedef base::Callback<void(ValueStore*)> StorageCallback; - // Must only be called from the FILE thread. |type| should be either // APP_SETTINGS or EXTENSION_SETTINGS. syncer::SyncableService* GetBackendForSync(syncer::ModelType type) const; - // Runs |callback| on the FILE thread with the storage area for - // |extension_id|. If there is no extension with that ID, the storage area - // will be NULL. + // Runs |callback| with the storage area of the given |settings_namespace| + // for the |extension_id|. If there is no extension with that ID, the storage + // area will be NULL. void RunWithStorage( const std::string& extension_id, settings_namespace::Namespace settings_namespace, - const StorageCallback& callback); + const ValueStoreCache::StorageCallback& callback); - // Deletes the settings for an extension (on the FILE thread). + // Deletes the settings for the given |extension_id|. void DeleteStorageSoon(const std::string& extension_id); // Gets the thread-safe observer list. scoped_refptr<SettingsObserverList> GetObservers(); private: + typedef std::map<settings_namespace::Namespace, ValueStoreCache*> CacheMap; + SettingsFrontend( const scoped_refptr<SettingsStorageFactory>& storage_factory, - // Ownership NOT taken. Profile* profile); // The quota limit configurations for the local and sync areas, taken out of @@ -84,18 +79,9 @@ class SettingsFrontend { // Observer for |profile_|. scoped_ptr<SettingsObserver> profile_observer_; - // Ref-counted container for each SettingsBackend object. There are 4: an - // apps and an extensions Backend for the LOCAL namespace, and likewise for - // the SYNC namespace. They only differ in what directory the database for - // each exists in. - class BackendWrapper; - struct BackendWrappers { - BackendWrappers(); - ~BackendWrappers(); - scoped_refptr<BackendWrapper> app; - scoped_refptr<BackendWrapper> extension; - }; - std::map<settings_namespace::Namespace, BackendWrappers> backends_; + // Maps a known namespace to its corresponding ValueStoreCache. The caches + // are owned by this object. + CacheMap caches_; DISALLOW_COPY_AND_ASSIGN(SettingsFrontend); }; diff --git a/chrome/browser/extensions/settings/settings_frontend_unittest.cc b/chrome/browser/extensions/settings/settings_frontend_unittest.cc index 05b404f..abd0115 100644 --- a/chrome/browser/extensions/settings/settings_frontend_unittest.cc +++ b/chrome/browser/extensions/settings/settings_frontend_unittest.cc @@ -80,6 +80,8 @@ class ExtensionSettingsFrontendTest : public testing::Test { virtual void TearDown() OVERRIDE { frontend_.reset(); profile_.reset(); + // Execute any pending deletion tasks. + message_loop_.RunAllPending(); } protected: diff --git a/chrome/browser/extensions/settings/settings_namespace.cc b/chrome/browser/extensions/settings/settings_namespace.cc index 7340592..82767ca 100644 --- a/chrome/browser/extensions/settings/settings_namespace.cc +++ b/chrome/browser/extensions/settings/settings_namespace.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -11,25 +11,29 @@ namespace extensions { namespace settings_namespace { namespace { -const char* kLocalNamespace = "local"; -const char* kSyncNamespace = "sync"; +const char kLocalNamespace[] = "local"; +const char kSyncNamespace[] = "sync"; +const char kManagedNamespace[] = "managed"; } // namespace std::string ToString(Namespace settings_namespace) { switch (settings_namespace) { - case LOCAL: return kLocalNamespace; - case SYNC: return kSyncNamespace; - case INVALID: - default: NOTREACHED(); + case LOCAL: return kLocalNamespace; + case SYNC: return kSyncNamespace; + case MANAGED: return kManagedNamespace; + case INVALID: break; } + NOTREACHED(); return std::string(); } Namespace FromString(const std::string& namespace_string) { if (namespace_string == kLocalNamespace) return LOCAL; - else if (namespace_string == kSyncNamespace) + if (namespace_string == kSyncNamespace) return SYNC; + if (namespace_string == kManagedNamespace) + return MANAGED; return INVALID; } diff --git a/chrome/browser/extensions/settings/settings_namespace.h b/chrome/browser/extensions/settings/settings_namespace.h index 2afdb02..c89658b 100644 --- a/chrome/browser/extensions/settings/settings_namespace.h +++ b/chrome/browser/extensions/settings/settings_namespace.h @@ -13,8 +13,9 @@ namespace settings_namespace { // The namespaces of the storage areas. enum Namespace { - LOCAL, // "local" i.e. chrome.storage.local - SYNC, // "sync" i.e. chrome.storage.sync + LOCAL, // "local" i.e. chrome.storage.local + SYNC, // "sync" i.e. chrome.storage.sync + MANAGED, // "managed" i.e. chrome.storage.managed INVALID }; diff --git a/chrome/browser/extensions/settings/settings_sync_unittest.cc b/chrome/browser/extensions/settings/settings_sync_unittest.cc index 7283bde..2af0a40 100644 --- a/chrome/browser/extensions/settings/settings_sync_unittest.cc +++ b/chrome/browser/extensions/settings/settings_sync_unittest.cc @@ -223,6 +223,8 @@ class ExtensionSettingsSyncTest : public testing::Test { virtual void TearDown() OVERRIDE { frontend_.reset(); profile_.reset(); + // Execute any pending deletion tasks. + message_loop_.RunAllPending(); } protected: diff --git a/chrome/browser/extensions/settings/sync_or_local_value_store_cache.cc b/chrome/browser/extensions/settings/sync_or_local_value_store_cache.cc new file mode 100644 index 0000000..21970ec --- /dev/null +++ b/chrome/browser/extensions/settings/sync_or_local_value_store_cache.cc @@ -0,0 +1,121 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/settings/sync_or_local_value_store_cache.h" + +#include "base/bind.h" +#include "base/callback.h" +#include "base/file_path.h" +#include "base/message_loop_proxy.h" +#include "base/sequenced_task_runner.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/settings/settings_backend.h" +#include "chrome/browser/extensions/settings/settings_frontend.h" +#include "chrome/browser/extensions/settings/settings_storage_quota_enforcer.h" +#include "chrome/browser/extensions/settings/weak_unlimited_settings_storage.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/permissions/api_permission.h" +#include "content/public/browser/browser_thread.h" + +using content::BrowserThread; + +namespace extensions { + +SyncOrLocalValueStoreCache::SyncOrLocalValueStoreCache( + settings_namespace::Namespace settings_namespace, + const scoped_refptr<SettingsStorageFactory>& factory, + const SettingsStorageQuotaEnforcer::Limits& quota, + const scoped_refptr<SettingsObserverList>& observers, + const FilePath& profile_path) + : settings_namespace_(settings_namespace) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(settings_namespace_ == settings_namespace::LOCAL || + settings_namespace_ == settings_namespace::SYNC); + + // This post is safe since the destructor can only be invoked from the + // same message loop, and any potential post of a deletion task must come + // after the constructor returns. + GetMessageLoop()->PostTask( + FROM_HERE, + base::Bind(&SyncOrLocalValueStoreCache::InitOnFileThread, + base::Unretained(this), + factory, quota, observers, profile_path)); +} + +SyncOrLocalValueStoreCache::~SyncOrLocalValueStoreCache() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); +} + +SettingsBackend* SyncOrLocalValueStoreCache::GetAppBackend() const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + DCHECK(app_backend_.get()); + return app_backend_.get(); +} + +SettingsBackend* SyncOrLocalValueStoreCache::GetExtensionBackend() const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + DCHECK(extension_backend_.get()); + return extension_backend_.get(); +} + +scoped_refptr<base::MessageLoopProxy> + SyncOrLocalValueStoreCache::GetMessageLoop() const { + return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE); +} + +void SyncOrLocalValueStoreCache::RunWithValueStoreForExtension( + const StorageCallback& callback, + scoped_refptr<const Extension> extension) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + DCHECK(app_backend_.get()); + DCHECK(extension_backend_.get()); + SettingsBackend* backend = + extension->is_app() ? app_backend_.get() : extension_backend_.get(); + ValueStore* storage = backend->GetStorage(extension->id()); + + // A neat way to implement unlimited storage; if the extension has the + // unlimited storage permission, force through all calls to Set() (in the + // same way that writes from sync ignore quota). + // But only if it's local storage (bad stuff would happen if sync'ed + // storage is allowed to be unlimited). + bool is_unlimited = + settings_namespace_ == settings_namespace::LOCAL && + extension->HasAPIPermission(APIPermission::kUnlimitedStorage); + + if (is_unlimited) { + WeakUnlimitedSettingsStorage unlimited_storage(storage); + callback.Run(&unlimited_storage); + } else { + callback.Run(storage); + } +} + +void SyncOrLocalValueStoreCache::DeleteStorageSoon( + const std::string& extension_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + app_backend_->DeleteStorage(extension_id); + extension_backend_->DeleteStorage(extension_id); +} + +void SyncOrLocalValueStoreCache::InitOnFileThread( + const scoped_refptr<SettingsStorageFactory>& factory, + const SettingsStorageQuotaEnforcer::Limits& quota, + const scoped_refptr<SettingsObserverList>& observers, + const FilePath& profile_path) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + DCHECK(!app_backend_.get()); + DCHECK(!extension_backend_.get()); + const bool local = settings_namespace_ == settings_namespace::LOCAL; + const FilePath app_path = profile_path.AppendASCII( + local ? ExtensionService::kLocalAppSettingsDirectoryName + : ExtensionService::kSyncAppSettingsDirectoryName); + const FilePath extension_path = profile_path.AppendASCII( + local ? ExtensionService::kLocalExtensionSettingsDirectoryName + : ExtensionService::kSyncExtensionSettingsDirectoryName); + app_backend_.reset(new SettingsBackend(factory, app_path, quota, observers)); + extension_backend_.reset( + new SettingsBackend(factory, extension_path, quota, observers)); +} + +} // namespace extensions diff --git a/chrome/browser/extensions/settings/sync_or_local_value_store_cache.h b/chrome/browser/extensions/settings/sync_or_local_value_store_cache.h new file mode 100644 index 0000000..667a083 --- /dev/null +++ b/chrome/browser/extensions/settings/sync_or_local_value_store_cache.h @@ -0,0 +1,64 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_SETTINGS_SYNC_OR_LOCAL_VALUE_STORE_CACHE_H_ +#define CHROME_BROWSER_EXTENSIONS_SETTINGS_SYNC_OR_LOCAL_VALUE_STORE_CACHE_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/extensions/settings/settings_observer.h" +#include "chrome/browser/extensions/settings/settings_storage_quota_enforcer.h" +#include "chrome/browser/extensions/settings/value_store_cache.h" + +class FilePath; + +namespace extensions { + +class SettingsBackend; +class SettingsStorageFactory; + +// ValueStoreCache for the LOCAL and SYNC namespaces. It owns a backend for +// apps and another for extensions. Each backend takes care of persistence and +// syncing. +class SyncOrLocalValueStoreCache : public ValueStoreCache { + public: + SyncOrLocalValueStoreCache( + settings_namespace::Namespace settings_namespace, + const scoped_refptr<SettingsStorageFactory>& factory, + const SettingsStorageQuotaEnforcer::Limits& quota, + const scoped_refptr<SettingsObserverList>& observers, + const FilePath& profile_path); + virtual ~SyncOrLocalValueStoreCache(); + + SettingsBackend* GetAppBackend() const; + SettingsBackend* GetExtensionBackend() const; + + // ValueStoreCache implementation: + + virtual scoped_refptr<base::MessageLoopProxy> GetMessageLoop() const OVERRIDE; + + virtual void RunWithValueStoreForExtension( + const StorageCallback& callback, + scoped_refptr<const Extension> extension) OVERRIDE; + + virtual void DeleteStorageSoon(const std::string& extension_id) OVERRIDE; + + private: + void InitOnFileThread(const scoped_refptr<SettingsStorageFactory>& factory, + const SettingsStorageQuotaEnforcer::Limits& quota, + const scoped_refptr<SettingsObserverList>& observers, + const FilePath& profile_path); + + settings_namespace::Namespace settings_namespace_; + scoped_ptr<SettingsBackend> app_backend_; + scoped_ptr<SettingsBackend> extension_backend_; + + DISALLOW_COPY_AND_ASSIGN(SyncOrLocalValueStoreCache); +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_SETTINGS_SYNC_OR_LOCAL_VALUE_STORE_CACHE_H_ diff --git a/chrome/browser/extensions/settings/value_store_cache.cc b/chrome/browser/extensions/settings/value_store_cache.cc new file mode 100644 index 0000000..8bcefb9 --- /dev/null +++ b/chrome/browser/extensions/settings/value_store_cache.cc @@ -0,0 +1,11 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/settings/value_store_cache.h" + +namespace extensions { + +ValueStoreCache::~ValueStoreCache() {} + +} // namespace extensions diff --git a/chrome/browser/extensions/settings/value_store_cache.h b/chrome/browser/extensions/settings/value_store_cache.h new file mode 100644 index 0000000..a891db9 --- /dev/null +++ b/chrome/browser/extensions/settings/value_store_cache.h @@ -0,0 +1,49 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_SETTINGS_VALUE_STORE_CACHE_H_ +#define CHROME_BROWSER_EXTENSIONS_SETTINGS_VALUE_STORE_CACHE_H_ + +#include <string> + +#include "base/callback.h" +#include "base/memory/ref_counted.h" +#include "base/message_loop_proxy.h" + +class ValueStore; + +namespace extensions { + +class Extension; + +// Each namespace of the storage API implements this interface. +// Instances are created on the UI thread, but from then on live on the loop +// returned by GetMessageLoop() and every methods (except GetMessageLoop()) +// are always called in that loop, including the destructor. +class ValueStoreCache { + public: + typedef base::Callback<void(ValueStore*)> StorageCallback; + + virtual ~ValueStoreCache(); + + // Returns the loop that the methods of this class should be invoked on. + virtual scoped_refptr<base::MessageLoopProxy> GetMessageLoop() const = 0; + + // Requests the cache to invoke |callback| with the appropriate ValueStore + // for the given |extension|. |callback| should be invoked with a NULL + // ValueStore in case of errors. + // |extension| is passed in a scoped_refptr<> because this method is + // asynchronously posted as a task to the loop returned by GetMessageLoop(), + // and this guarantees the Extension is still valid when the method executes. + virtual void RunWithValueStoreForExtension( + const StorageCallback& callback, + scoped_refptr<const Extension> extension) = 0; + + // Requests the cache to delete any storage used by |extension_id|. + virtual void DeleteStorageSoon(const std::string& extension_id) = 0; +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_SETTINGS_VALUE_STORE_CACHE_H_ diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index e08f721..c0bb8d6 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi @@ -456,6 +456,8 @@ 'browser/extensions/script_executor.h', 'browser/extensions/settings/leveldb_settings_storage_factory.cc', 'browser/extensions/settings/leveldb_settings_storage_factory.h', + 'browser/extensions/settings/managed_value_store_cache.cc', + 'browser/extensions/settings/managed_value_store_cache.h', 'browser/extensions/settings/setting_sync_data.cc', 'browser/extensions/settings/setting_sync_data.h', 'browser/extensions/settings/settings_backend.cc', @@ -472,8 +474,12 @@ 'browser/extensions/settings/settings_sync_processor.h', 'browser/extensions/settings/settings_sync_util.cc', 'browser/extensions/settings/settings_sync_util.h', + 'browser/extensions/settings/sync_or_local_value_store_cache.cc', + 'browser/extensions/settings/sync_or_local_value_store_cache.h', 'browser/extensions/settings/syncable_settings_storage.cc', 'browser/extensions/settings/syncable_settings_storage.h', + 'browser/extensions/settings/value_store_cache.cc', + 'browser/extensions/settings/value_store_cache.h', 'browser/extensions/settings/weak_unlimited_settings_storage.cc', 'browser/extensions/settings/weak_unlimited_settings_storage.h', 'browser/extensions/shell_window_registry.cc', |