1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/extensions/api/storage/settings_frontend.h" 6 7 #include <limits> 8 9 #include "base/bind.h" 10 #include "base/bind_helpers.h" 11 #include "base/files/file_path.h" 12 #include "base/json/json_reader.h" 13 #include "chrome/browser/extensions/api/storage/leveldb_settings_storage_factory.h" 14 #include "chrome/browser/extensions/api/storage/settings_backend.h" 15 #include "chrome/browser/extensions/api/storage/sync_or_local_value_store_cache.h" 16 #include "chrome/browser/extensions/event_names.h" 17 #include "chrome/browser/extensions/event_router.h" 18 #include "chrome/browser/extensions/extension_service.h" 19 #include "chrome/browser/extensions/extension_system.h" 20 #include "chrome/browser/profiles/profile.h" 21 #include "chrome/common/extensions/api/storage.h" 22 #include "content/public/browser/browser_thread.h" 23 24 #if defined(ENABLE_CONFIGURATION_POLICY) 25 #include "chrome/browser/extensions/api/storage/managed_value_store_cache.h" 26 #endif 27 28 using content::BrowserThread; 29 30 namespace extensions { 31 32 namespace { 33 34 // Settings change Observer which forwards changes on to the extension 35 // processes for |profile| and its incognito partner if it exists. 36 class DefaultObserver : public SettingsObserver { 37 public: 38 explicit DefaultObserver(Profile* profile) : profile_(profile) {} 39 40 // SettingsObserver implementation. 41 virtual void OnSettingsChanged( 42 const std::string& extension_id, 43 settings_namespace::Namespace settings_namespace, 44 const std::string& change_json) OVERRIDE { 45 // TODO(gdk): This is a temporary hack while the refactoring for 46 // string-based event payloads is removed. http://crbug.com/136045 47 scoped_ptr<base::ListValue> args(new base::ListValue()); 48 args->Append(base::JSONReader::Read(change_json)); 49 args->Append(Value::CreateStringValue(settings_namespace::ToString( 50 settings_namespace))); 51 scoped_ptr<Event> event(new Event( 52 event_names::kOnSettingsChanged, args.Pass())); 53 ExtensionSystem::Get(profile_)->event_router()-> 54 DispatchEventToExtension(extension_id, event.Pass()); 55 } 56 57 private: 58 Profile* const profile_; 59 }; 60 61 SettingsStorageQuotaEnforcer::Limits GetLocalLimits() { 62 SettingsStorageQuotaEnforcer::Limits limits = { 63 static_cast<size_t>(api::storage::local::QUOTA_BYTES), 64 std::numeric_limits<size_t>::max(), 65 std::numeric_limits<size_t>::max() 66 }; 67 return limits; 68 } 69 70 SettingsStorageQuotaEnforcer::Limits GetSyncLimits() { 71 SettingsStorageQuotaEnforcer::Limits limits = { 72 static_cast<size_t>(api::storage::sync::QUOTA_BYTES), 73 static_cast<size_t>(api::storage::sync::QUOTA_BYTES_PER_ITEM), 74 static_cast<size_t>(api::storage::sync::MAX_ITEMS) 75 }; 76 return limits; 77 } 78 79 } // namespace 80 81 // static 82 SettingsFrontend* SettingsFrontend::Create(Profile* profile) { 83 return new SettingsFrontend(new LeveldbSettingsStorageFactory(), profile); 84 } 85 86 // static 87 SettingsFrontend* SettingsFrontend::Create( 88 const scoped_refptr<SettingsStorageFactory>& storage_factory, 89 Profile* profile) { 90 return new SettingsFrontend(storage_factory, profile); 91 } 92 93 SettingsFrontend::SettingsFrontend( 94 const scoped_refptr<SettingsStorageFactory>& factory, Profile* profile) 95 : local_quota_limit_(GetLocalLimits()), 96 sync_quota_limit_(GetSyncLimits()), 97 profile_(profile), 98 observers_(new SettingsObserverList()), 99 profile_observer_(new DefaultObserver(profile)) { 100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 101 DCHECK(!profile->IsOffTheRecord()); 102 103 observers_->AddObserver(profile_observer_.get()); 104 105 const base::FilePath& profile_path = profile->GetPath(); 106 caches_[settings_namespace::LOCAL] = 107 new SyncOrLocalValueStoreCache( 108 settings_namespace::LOCAL, 109 factory, 110 local_quota_limit_, 111 observers_, 112 profile_path); 113 caches_[settings_namespace::SYNC] = 114 new SyncOrLocalValueStoreCache( 115 settings_namespace::SYNC, 116 factory, 117 sync_quota_limit_, 118 observers_, 119 profile_path); 120 121 #if defined(ENABLE_CONFIGURATION_POLICY) 122 caches_[settings_namespace::MANAGED] = 123 new ManagedValueStoreCache( 124 profile, 125 factory, 126 observers_); 127 #endif 128 } 129 130 SettingsFrontend::~SettingsFrontend() { 131 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 132 observers_->RemoveObserver(profile_observer_.get()); 133 for (CacheMap::iterator it = caches_.begin(); it != caches_.end(); ++it) { 134 ValueStoreCache* cache = it->second; 135 cache->ShutdownOnUI(); 136 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, cache); 137 } 138 } 139 140 syncer::SyncableService* SettingsFrontend::GetBackendForSync( 141 syncer::ModelType type) const { 142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 143 CacheMap::const_iterator it = caches_.find(settings_namespace::SYNC); 144 DCHECK(it != caches_.end()); 145 const SyncOrLocalValueStoreCache* sync_cache = 146 static_cast<const SyncOrLocalValueStoreCache*>(it->second); 147 switch (type) { 148 case syncer::APP_SETTINGS: 149 return sync_cache->GetAppBackend(); 150 case syncer::EXTENSION_SETTINGS: 151 return sync_cache->GetExtensionBackend(); 152 default: 153 NOTREACHED(); 154 return NULL; 155 } 156 } 157 158 bool SettingsFrontend::IsStorageEnabled( 159 settings_namespace::Namespace settings_namespace) const { 160 return caches_.find(settings_namespace) != caches_.end(); 161 } 162 163 void SettingsFrontend::RunWithStorage( 164 const std::string& extension_id, 165 settings_namespace::Namespace settings_namespace, 166 const ValueStoreCache::StorageCallback& callback) { 167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 168 169 ValueStoreCache* cache = caches_[settings_namespace]; 170 CHECK(cache); 171 172 // The |extension| has already been referenced earlier in the stack, so it 173 // can't be gone here. 174 // TODO(kalman): change RunWithStorage() to take a 175 // scoped_refptr<const Extension> instead. 176 scoped_refptr<const Extension> extension = 177 extensions::ExtensionSystem::Get(profile_)->extension_service()-> 178 GetExtensionById(extension_id, true); 179 CHECK(extension.get()); 180 181 BrowserThread::PostTask( 182 BrowserThread::FILE, FROM_HERE, 183 base::Bind(&ValueStoreCache::RunWithValueStoreForExtension, 184 base::Unretained(cache), callback, extension)); 185 } 186 187 void SettingsFrontend::DeleteStorageSoon( 188 const std::string& extension_id) { 189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 190 for (CacheMap::iterator it = caches_.begin(); it != caches_.end(); ++it) { 191 ValueStoreCache* cache = it->second; 192 BrowserThread::PostTask( 193 BrowserThread::FILE, FROM_HERE, 194 base::Bind(&ValueStoreCache::DeleteStorageSoon, 195 base::Unretained(cache), 196 extension_id)); 197 } 198 } 199 200 scoped_refptr<SettingsObserverList> SettingsFrontend::GetObservers() { 201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 202 return observers_; 203 } 204 205 void SettingsFrontend::DisableStorageForTesting( 206 settings_namespace::Namespace settings_namespace) { 207 CacheMap::iterator it = caches_.find(settings_namespace); 208 if (it != caches_.end()) { 209 ValueStoreCache* cache = it->second; 210 cache->ShutdownOnUI(); 211 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, cache); 212 caches_.erase(it); 213 } 214 } 215 216 } // namespace extensions 217