// 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/api/storage/settings_frontend.h" #include #include "base/bind.h" #include "base/bind_helpers.h" #include "base/files/file_path.h" #include "base/json/json_reader.h" #include "chrome/browser/extensions/api/storage/leveldb_settings_storage_factory.h" #include "chrome/browser/extensions/api/storage/settings_backend.h" #include "chrome/browser/extensions/api/storage/sync_or_local_value_store_cache.h" #include "chrome/browser/extensions/event_names.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/api/storage.h" #include "content/public/browser/browser_thread.h" #include "extensions/browser/event_router.h" #include "extensions/browser/extension_system.h" #if defined(ENABLE_CONFIGURATION_POLICY) #include "chrome/browser/extensions/api/storage/managed_value_store_cache.h" #endif using content::BrowserThread; namespace extensions { namespace storage = api::storage; namespace { // Settings change Observer which forwards changes on to the extension // processes for |profile| and its incognito partner if it exists. class DefaultObserver : public SettingsObserver { public: explicit DefaultObserver(Profile* profile) : profile_(profile) {} // SettingsObserver implementation. virtual void OnSettingsChanged( const std::string& extension_id, settings_namespace::Namespace settings_namespace, const std::string& change_json) OVERRIDE { // TODO(gdk): This is a temporary hack while the refactoring for // string-based event payloads is removed. http://crbug.com/136045 scoped_ptr args(new base::ListValue()); args->Append(base::JSONReader::Read(change_json)); args->Append(new base::StringValue(settings_namespace::ToString( settings_namespace))); scoped_ptr event(new Event( storage::OnChanged::kEventName, args.Pass())); ExtensionSystem::Get(profile_)->event_router()-> DispatchEventToExtension(extension_id, event.Pass()); } private: Profile* const profile_; }; SettingsStorageQuotaEnforcer::Limits GetLocalLimits() { SettingsStorageQuotaEnforcer::Limits limits = { static_cast(api::storage::local::QUOTA_BYTES), std::numeric_limits::max(), std::numeric_limits::max() }; return limits; } SettingsStorageQuotaEnforcer::Limits GetSyncLimits() { SettingsStorageQuotaEnforcer::Limits limits = { static_cast(api::storage::sync::QUOTA_BYTES), static_cast(api::storage::sync::QUOTA_BYTES_PER_ITEM), static_cast(api::storage::sync::MAX_ITEMS) }; return limits; } } // namespace // static SettingsFrontend* SettingsFrontend::Create(Profile* profile) { return new SettingsFrontend(new LeveldbSettingsStorageFactory(), profile); } // static SettingsFrontend* SettingsFrontend::Create( const scoped_refptr& storage_factory, Profile* profile) { return new SettingsFrontend(storage_factory, profile); } SettingsFrontend::SettingsFrontend( const scoped_refptr& factory, Profile* profile) : local_quota_limit_(GetLocalLimits()), sync_quota_limit_(GetSyncLimits()), profile_(profile), observers_(new SettingsObserverList()), profile_observer_(new DefaultObserver(profile)) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(!profile->IsOffTheRecord()); observers_->AddObserver(profile_observer_.get()); const base::FilePath& profile_path = profile->GetPath(); caches_[settings_namespace::LOCAL] = new SyncOrLocalValueStoreCache( settings_namespace::LOCAL, factory, local_quota_limit_, observers_, profile_path); caches_[settings_namespace::SYNC] = new SyncOrLocalValueStoreCache( settings_namespace::SYNC, factory, sync_quota_limit_, observers_, profile_path); #if defined(ENABLE_CONFIGURATION_POLICY) caches_[settings_namespace::MANAGED] = new ManagedValueStoreCache( profile, factory, observers_); #endif } SettingsFrontend::~SettingsFrontend() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); observers_->RemoveObserver(profile_observer_.get()); for (CacheMap::iterator it = caches_.begin(); it != caches_.end(); ++it) { ValueStoreCache* cache = it->second; cache->ShutdownOnUI(); BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, cache); } } syncer::SyncableService* SettingsFrontend::GetBackendForSync( syncer::ModelType type) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); CacheMap::const_iterator it = caches_.find(settings_namespace::SYNC); DCHECK(it != caches_.end()); const SyncOrLocalValueStoreCache* sync_cache = static_cast(it->second); switch (type) { case syncer::APP_SETTINGS: return sync_cache->GetAppBackend(); case syncer::EXTENSION_SETTINGS: return sync_cache->GetExtensionBackend(); default: NOTREACHED(); return NULL; } } bool SettingsFrontend::IsStorageEnabled( settings_namespace::Namespace settings_namespace) const { return caches_.find(settings_namespace) != caches_.end(); } void SettingsFrontend::RunWithStorage( const std::string& extension_id, settings_namespace::Namespace settings_namespace, const ValueStoreCache::StorageCallback& callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); ValueStoreCache* cache = caches_[settings_namespace]; CHECK(cache); // The |extension| has already been referenced earlier in the stack, so it // can't be gone here. // TODO(kalman): change RunWithStorage() to take a // scoped_refptr instead. scoped_refptr extension = extensions::ExtensionSystem::Get(profile_)->extension_service()-> GetExtensionById(extension_id, true); CHECK(extension.get()); BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, base::Bind(&ValueStoreCache::RunWithValueStoreForExtension, base::Unretained(cache), callback, extension)); } void SettingsFrontend::DeleteStorageSoon( const std::string& extension_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); for (CacheMap::iterator it = caches_.begin(); it != caches_.end(); ++it) { ValueStoreCache* cache = it->second; BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, base::Bind(&ValueStoreCache::DeleteStorageSoon, base::Unretained(cache), extension_id)); } } scoped_refptr SettingsFrontend::GetObservers() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); return observers_; } void SettingsFrontend::DisableStorageForTesting( settings_namespace::Namespace settings_namespace) { CacheMap::iterator it = caches_.find(settings_namespace); if (it != caches_.end()) { ValueStoreCache* cache = it->second; cache->ShutdownOnUI(); BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, cache); caches_.erase(it); } } } // namespace extensions