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 "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"
21 using content::BrowserContext
;
22 using content::BrowserThread
;
24 namespace extensions
{
28 base::LazyInstance
<BrowserContextKeyedAPIFactory
<StorageFrontend
> > g_factory
=
29 LAZY_INSTANCE_INITIALIZER
;
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
{
35 explicit DefaultObserver(BrowserContext
* context
)
36 : browser_context_(context
) {}
38 // SettingsObserver implementation.
39 void OnSettingsChanged(const std::string
& extension_id
,
40 settings_namespace::Namespace settings_namespace
,
41 const std::string
& change_json
) override
{
42 // TODO(gdk): This is a temporary hack while the refactoring for
43 // string-based event payloads is removed. http://crbug.com/136045
44 scoped_ptr
<base::ListValue
> args(new base::ListValue());
45 args
->Append(base::JSONReader::Read(change_json
));
46 args
->Append(new base::StringValue(settings_namespace::ToString(
47 settings_namespace
)));
48 scoped_ptr
<Event
> event(new Event(
49 core_api::storage::OnChanged::kEventName
, args
.Pass()));
50 EventRouter::Get(browser_context_
)
51 ->DispatchEventToExtension(extension_id
, event
.Pass());
55 BrowserContext
* const browser_context_
;
61 StorageFrontend
* StorageFrontend::Get(BrowserContext
* context
) {
62 return BrowserContextKeyedAPIFactory
<StorageFrontend
>::Get(context
);
66 StorageFrontend
* StorageFrontend::CreateForTesting(
67 const scoped_refptr
<SettingsStorageFactory
>& storage_factory
,
68 BrowserContext
* context
) {
69 return new StorageFrontend(storage_factory
, context
);
72 StorageFrontend::StorageFrontend(BrowserContext
* context
)
73 : browser_context_(context
) {
74 Init(new LeveldbSettingsStorageFactory());
77 StorageFrontend::StorageFrontend(
78 const scoped_refptr
<SettingsStorageFactory
>& factory
,
79 BrowserContext
* context
)
80 : browser_context_(context
) {
84 void StorageFrontend::Init(
85 const scoped_refptr
<SettingsStorageFactory
>& factory
) {
86 observers_
= new SettingsObserverList();
87 browser_context_observer_
.reset(new DefaultObserver(browser_context_
));
88 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
89 DCHECK(!browser_context_
->IsOffTheRecord());
91 observers_
->AddObserver(browser_context_observer_
.get());
93 caches_
[settings_namespace::LOCAL
] =
94 new LocalValueStoreCache(factory
, browser_context_
->GetPath());
96 // Add any additional caches the embedder supports (for example, caches
97 // for chrome.storage.managed and chrome.storage.sync).
98 ExtensionsAPIClient::Get()->AddAdditionalValueStoreCaches(
99 browser_context_
, factory
, observers_
, &caches_
);
102 StorageFrontend::~StorageFrontend() {
103 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
104 observers_
->RemoveObserver(browser_context_observer_
.get());
105 for (CacheMap::iterator it
= caches_
.begin(); it
!= caches_
.end(); ++it
) {
106 ValueStoreCache
* cache
= it
->second
;
107 cache
->ShutdownOnUI();
108 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE
, cache
);
112 ValueStoreCache
* StorageFrontend::GetValueStoreCache(
113 settings_namespace::Namespace settings_namespace
) const {
114 CacheMap::const_iterator it
= caches_
.find(settings_namespace
);
115 if (it
!= caches_
.end())
120 bool StorageFrontend::IsStorageEnabled(
121 settings_namespace::Namespace settings_namespace
) const {
122 return caches_
.find(settings_namespace
) != caches_
.end();
125 void StorageFrontend::RunWithStorage(
126 scoped_refptr
<const Extension
> extension
,
127 settings_namespace::Namespace settings_namespace
,
128 const ValueStoreCache::StorageCallback
& callback
) {
129 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
130 CHECK(extension
.get());
132 ValueStoreCache
* cache
= caches_
[settings_namespace
];
135 BrowserThread::PostTask(
136 BrowserThread::FILE, FROM_HERE
,
137 base::Bind(&ValueStoreCache::RunWithValueStoreForExtension
,
138 base::Unretained(cache
), callback
, extension
));
141 void StorageFrontend::DeleteStorageSoon(const std::string
& extension_id
) {
142 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
143 for (CacheMap::iterator it
= caches_
.begin(); it
!= caches_
.end(); ++it
) {
144 ValueStoreCache
* cache
= it
->second
;
145 BrowserThread::PostTask(
146 BrowserThread::FILE, FROM_HERE
,
147 base::Bind(&ValueStoreCache::DeleteStorageSoon
,
148 base::Unretained(cache
),
153 scoped_refptr
<SettingsObserverList
> StorageFrontend::GetObservers() {
154 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
158 void StorageFrontend::DisableStorageForTesting(
159 settings_namespace::Namespace settings_namespace
) {
160 CacheMap::iterator it
= caches_
.find(settings_namespace
);
161 if (it
!= caches_
.end()) {
162 ValueStoreCache
* cache
= it
->second
;
163 cache
->ShutdownOnUI();
164 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE
, cache
);
169 // BrowserContextKeyedAPI implementation.
172 BrowserContextKeyedAPIFactory
<StorageFrontend
>*
173 StorageFrontend::GetFactoryInstance() {
174 return g_factory
.Pointer();
178 const char* StorageFrontend::service_name() { return "StorageFrontend"; }
180 } // namespace extensions