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