1 // Copyright 2014 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 "extensions/browser/api/storage/storage_frontend.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/files/file_path.h"
10 #include "base/json/json_reader.h"
11 #include "base/lazy_instance.h"
12 #include "content/public/browser/browser_context.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "extensions/browser/api/extensions_api_client.h"
15 #include "extensions/browser/api/storage/leveldb_settings_storage_factory.h"
16 #include "extensions/browser/api/storage/local_value_store_cache.h"
17 #include "extensions/browser/event_router.h"
18 #include "extensions/browser/extension_registry.h"
19 #include "extensions/common/api/storage.h"
20
21 using content::BrowserContext;
22 using content::BrowserThread;
23
24 namespace extensions {
25
26 namespace {
27
28 base::LazyInstance<BrowserContextKeyedAPIFactory<StorageFrontend> > g_factory =
29 LAZY_INSTANCE_INITIALIZER;
30
31 // Settings change Observer which forwards changes on to the extension
32 // processes for |context| and its incognito partner if it exists.
33 class DefaultObserver : public SettingsObserver {
34 public:
DefaultObserver(BrowserContext * context)35 explicit DefaultObserver(BrowserContext* context)
36 : browser_context_(context) {}
37
38 // SettingsObserver implementation.
OnSettingsChanged(const std::string & extension_id,settings_namespace::Namespace settings_namespace,const std::string & change_json)39 virtual void OnSettingsChanged(
40 const std::string& extension_id,
41 settings_namespace::Namespace settings_namespace,
42 const std::string& change_json) OVERRIDE {
43 // TODO(gdk): This is a temporary hack while the refactoring for
44 // string-based event payloads is removed. http://crbug.com/136045
45 scoped_ptr<base::ListValue> args(new base::ListValue());
46 args->Append(base::JSONReader::Read(change_json));
47 args->Append(new base::StringValue(settings_namespace::ToString(
48 settings_namespace)));
49 scoped_ptr<Event> event(new Event(
50 core_api::storage::OnChanged::kEventName, args.Pass()));
51 EventRouter::Get(browser_context_)
52 ->DispatchEventToExtension(extension_id, event.Pass());
53 }
54
55 private:
56 BrowserContext* const browser_context_;
57 };
58
59 } // namespace
60
61 // static
Get(BrowserContext * context)62 StorageFrontend* StorageFrontend::Get(BrowserContext* context) {
63 return BrowserContextKeyedAPIFactory<StorageFrontend>::Get(context);
64 }
65
66 // static
CreateForTesting(const scoped_refptr<SettingsStorageFactory> & storage_factory,BrowserContext * context)67 StorageFrontend* StorageFrontend::CreateForTesting(
68 const scoped_refptr<SettingsStorageFactory>& storage_factory,
69 BrowserContext* context) {
70 return new StorageFrontend(storage_factory, context);
71 }
72
StorageFrontend(BrowserContext * context)73 StorageFrontend::StorageFrontend(BrowserContext* context)
74 : browser_context_(context) {
75 Init(new LeveldbSettingsStorageFactory());
76 }
77
StorageFrontend(const scoped_refptr<SettingsStorageFactory> & factory,BrowserContext * context)78 StorageFrontend::StorageFrontend(
79 const scoped_refptr<SettingsStorageFactory>& factory,
80 BrowserContext* context)
81 : browser_context_(context) {
82 Init(factory);
83 }
84
Init(const scoped_refptr<SettingsStorageFactory> & factory)85 void StorageFrontend::Init(
86 const scoped_refptr<SettingsStorageFactory>& factory) {
87 observers_ = new SettingsObserverList();
88 browser_context_observer_.reset(new DefaultObserver(browser_context_));
89 DCHECK_CURRENTLY_ON(BrowserThread::UI);
90 DCHECK(!browser_context_->IsOffTheRecord());
91
92 observers_->AddObserver(browser_context_observer_.get());
93
94 caches_[settings_namespace::LOCAL] =
95 new LocalValueStoreCache(factory, browser_context_->GetPath());
96
97 // Add any additional caches the embedder supports (for example, caches
98 // for chrome.storage.managed and chrome.storage.sync).
99 ExtensionsAPIClient::Get()->AddAdditionalValueStoreCaches(
100 browser_context_, factory, observers_, &caches_);
101 }
102
~StorageFrontend()103 StorageFrontend::~StorageFrontend() {
104 DCHECK_CURRENTLY_ON(BrowserThread::UI);
105 observers_->RemoveObserver(browser_context_observer_.get());
106 for (CacheMap::iterator it = caches_.begin(); it != caches_.end(); ++it) {
107 ValueStoreCache* cache = it->second;
108 cache->ShutdownOnUI();
109 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, cache);
110 }
111 }
112
GetValueStoreCache(settings_namespace::Namespace settings_namespace) const113 ValueStoreCache* StorageFrontend::GetValueStoreCache(
114 settings_namespace::Namespace settings_namespace) const {
115 CacheMap::const_iterator it = caches_.find(settings_namespace);
116 if (it != caches_.end())
117 return it->second;
118 return NULL;
119 }
120
IsStorageEnabled(settings_namespace::Namespace settings_namespace) const121 bool StorageFrontend::IsStorageEnabled(
122 settings_namespace::Namespace settings_namespace) const {
123 return caches_.find(settings_namespace) != caches_.end();
124 }
125
RunWithStorage(scoped_refptr<const Extension> extension,settings_namespace::Namespace settings_namespace,const ValueStoreCache::StorageCallback & callback)126 void StorageFrontend::RunWithStorage(
127 scoped_refptr<const Extension> extension,
128 settings_namespace::Namespace settings_namespace,
129 const ValueStoreCache::StorageCallback& callback) {
130 DCHECK_CURRENTLY_ON(BrowserThread::UI);
131 CHECK(extension.get());
132
133 ValueStoreCache* cache = caches_[settings_namespace];
134 CHECK(cache);
135
136 BrowserThread::PostTask(
137 BrowserThread::FILE, FROM_HERE,
138 base::Bind(&ValueStoreCache::RunWithValueStoreForExtension,
139 base::Unretained(cache), callback, extension));
140 }
141
DeleteStorageSoon(const std::string & extension_id)142 void StorageFrontend::DeleteStorageSoon(const std::string& extension_id) {
143 DCHECK_CURRENTLY_ON(BrowserThread::UI);
144 for (CacheMap::iterator it = caches_.begin(); it != caches_.end(); ++it) {
145 ValueStoreCache* cache = it->second;
146 BrowserThread::PostTask(
147 BrowserThread::FILE, FROM_HERE,
148 base::Bind(&ValueStoreCache::DeleteStorageSoon,
149 base::Unretained(cache),
150 extension_id));
151 }
152 }
153
GetObservers()154 scoped_refptr<SettingsObserverList> StorageFrontend::GetObservers() {
155 DCHECK_CURRENTLY_ON(BrowserThread::UI);
156 return observers_;
157 }
158
DisableStorageForTesting(settings_namespace::Namespace settings_namespace)159 void StorageFrontend::DisableStorageForTesting(
160 settings_namespace::Namespace settings_namespace) {
161 CacheMap::iterator it = caches_.find(settings_namespace);
162 if (it != caches_.end()) {
163 ValueStoreCache* cache = it->second;
164 cache->ShutdownOnUI();
165 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, cache);
166 caches_.erase(it);
167 }
168 }
169
170 // BrowserContextKeyedAPI implementation.
171
172 // static
173 BrowserContextKeyedAPIFactory<StorageFrontend>*
GetFactoryInstance()174 StorageFrontend::GetFactoryInstance() {
175 return g_factory.Pointer();
176 }
177
178 // static
service_name()179 const char* StorageFrontend::service_name() { return "StorageFrontend"; }
180
181 } // namespace extensions
182