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.
5 #include "extensions/browser/api/storage/storage_frontend.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 "base/metrics/histogram_macros.h"
13 #include "base/trace_event/trace_event.h"
14 #include "content/public/browser/browser_context.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "extensions/browser/api/extensions_api_client.h"
17 #include "extensions/browser/api/storage/leveldb_settings_storage_factory.h"
18 #include "extensions/browser/api/storage/local_value_store_cache.h"
19 #include "extensions/browser/event_router.h"
20 #include "extensions/browser/extension_registry.h"
21 #include "extensions/common/api/storage.h"
23 using content::BrowserContext
;
24 using content::BrowserThread
;
26 namespace extensions
{
30 base::LazyInstance
<BrowserContextKeyedAPIFactory
<StorageFrontend
> > g_factory
=
31 LAZY_INSTANCE_INITIALIZER
;
33 // Settings change Observer which forwards changes on to the extension
34 // processes for |context| and its incognito partner if it exists.
35 class DefaultObserver
: public SettingsObserver
{
37 explicit DefaultObserver(BrowserContext
* context
)
38 : browser_context_(context
) {}
40 // SettingsObserver implementation.
41 void OnSettingsChanged(const std::string
& extension_id
,
42 settings_namespace::Namespace settings_namespace
,
43 const std::string
& change_json
) override
{
44 // TODO(gdk): This is a temporary hack while the refactoring for
45 // string-based event payloads is removed. http://crbug.com/136045
46 scoped_ptr
<base::ListValue
> args(new base::ListValue());
47 args
->Append(base::JSONReader::Read(change_json
));
48 args
->Append(new base::StringValue(settings_namespace::ToString(
49 settings_namespace
)));
50 scoped_ptr
<Event
> event(new Event(
51 core_api::storage::OnChanged::kEventName
, args
.Pass()));
52 EventRouter::Get(browser_context_
)
53 ->DispatchEventToExtension(extension_id
, event
.Pass());
57 BrowserContext
* const browser_context_
;
63 StorageFrontend
* StorageFrontend::Get(BrowserContext
* context
) {
64 return BrowserContextKeyedAPIFactory
<StorageFrontend
>::Get(context
);
68 StorageFrontend
* StorageFrontend::CreateForTesting(
69 const scoped_refptr
<SettingsStorageFactory
>& storage_factory
,
70 BrowserContext
* context
) {
71 return new StorageFrontend(storage_factory
, context
);
74 StorageFrontend::StorageFrontend(BrowserContext
* context
)
75 : browser_context_(context
) {
76 Init(new LeveldbSettingsStorageFactory());
79 StorageFrontend::StorageFrontend(
80 const scoped_refptr
<SettingsStorageFactory
>& factory
,
81 BrowserContext
* context
)
82 : browser_context_(context
) {
86 void StorageFrontend::Init(
87 const scoped_refptr
<SettingsStorageFactory
>& factory
) {
88 TRACE_EVENT0("browser,startup", "StorageFrontend::Init")
89 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.StorageFrontendInitTime");
91 observers_
= new SettingsObserverList();
92 browser_context_observer_
.reset(new DefaultObserver(browser_context_
));
93 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
94 DCHECK(!browser_context_
->IsOffTheRecord());
96 observers_
->AddObserver(browser_context_observer_
.get());
98 caches_
[settings_namespace::LOCAL
] =
99 new LocalValueStoreCache(factory
, browser_context_
->GetPath());
101 // Add any additional caches the embedder supports (for example, caches
102 // for chrome.storage.managed and chrome.storage.sync).
103 ExtensionsAPIClient::Get()->AddAdditionalValueStoreCaches(
104 browser_context_
, factory
, observers_
, &caches_
);
107 StorageFrontend::~StorageFrontend() {
108 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
109 observers_
->RemoveObserver(browser_context_observer_
.get());
110 for (CacheMap::iterator it
= caches_
.begin(); it
!= caches_
.end(); ++it
) {
111 ValueStoreCache
* cache
= it
->second
;
112 cache
->ShutdownOnUI();
113 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE
, cache
);
117 ValueStoreCache
* StorageFrontend::GetValueStoreCache(
118 settings_namespace::Namespace settings_namespace
) const {
119 CacheMap::const_iterator it
= caches_
.find(settings_namespace
);
120 if (it
!= caches_
.end())
125 bool StorageFrontend::IsStorageEnabled(
126 settings_namespace::Namespace settings_namespace
) const {
127 return caches_
.find(settings_namespace
) != caches_
.end();
130 void StorageFrontend::RunWithStorage(
131 scoped_refptr
<const Extension
> extension
,
132 settings_namespace::Namespace settings_namespace
,
133 const ValueStoreCache::StorageCallback
& callback
) {
134 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
135 CHECK(extension
.get());
137 ValueStoreCache
* cache
= caches_
[settings_namespace
];
140 BrowserThread::PostTask(
141 BrowserThread::FILE, FROM_HERE
,
142 base::Bind(&ValueStoreCache::RunWithValueStoreForExtension
,
143 base::Unretained(cache
), callback
, extension
));
146 void StorageFrontend::DeleteStorageSoon(const std::string
& extension_id
) {
147 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
148 for (CacheMap::iterator it
= caches_
.begin(); it
!= caches_
.end(); ++it
) {
149 ValueStoreCache
* cache
= it
->second
;
150 BrowserThread::PostTask(
151 BrowserThread::FILE, FROM_HERE
,
152 base::Bind(&ValueStoreCache::DeleteStorageSoon
,
153 base::Unretained(cache
),
158 scoped_refptr
<SettingsObserverList
> StorageFrontend::GetObservers() {
159 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
163 void StorageFrontend::DisableStorageForTesting(
164 settings_namespace::Namespace settings_namespace
) {
165 CacheMap::iterator it
= caches_
.find(settings_namespace
);
166 if (it
!= caches_
.end()) {
167 ValueStoreCache
* cache
= it
->second
;
168 cache
->ShutdownOnUI();
169 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE
, cache
);
174 // BrowserContextKeyedAPI implementation.
177 BrowserContextKeyedAPIFactory
<StorageFrontend
>*
178 StorageFrontend::GetFactoryInstance() {
179 return g_factory
.Pointer();
183 const char* StorageFrontend::service_name() { return "StorageFrontend"; }
185 } // namespace extensions