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/state_store.h"
8 #include "base/message_loop/message_loop.h"
9 #include "content/public/browser/browser_context.h"
10 #include "content/public/browser/notification_service.h"
11 #include "content/public/browser/notification_types.h"
12 #include "extensions/browser/extension_registry.h"
13 #include "extensions/common/extension.h"
17 // Delay, in seconds, before we should open the State Store database. We
18 // defer it to avoid slowing down startup. See http://crbug.com/161848
19 const int kInitDelaySeconds
= 1;
21 std::string
GetFullKey(const std::string
& extension_id
,
22 const std::string
& key
) {
23 return extension_id
+ "." + key
;
28 namespace extensions
{
30 // Helper class to delay tasks until we're ready to start executing them.
31 class StateStore::DelayedTaskQueue
{
33 DelayedTaskQueue() : ready_(false) {}
34 ~DelayedTaskQueue() {}
36 // Queues up a task for invoking once we're ready. Invokes immediately if
37 // we're already ready.
38 void InvokeWhenReady(base::Closure task
);
40 // Marks us ready, and invokes all pending tasks.
43 // Return whether or not the DelayedTaskQueue is |ready_|.
44 bool ready() const { return ready_
; }
48 std::vector
<base::Closure
> pending_tasks_
;
51 void StateStore::DelayedTaskQueue::InvokeWhenReady(base::Closure task
) {
55 pending_tasks_
.push_back(task
);
59 void StateStore::DelayedTaskQueue::SetReady() {
62 for (size_t i
= 0; i
< pending_tasks_
.size(); ++i
)
63 pending_tasks_
[i
].Run();
64 pending_tasks_
.clear();
67 StateStore::StateStore(content::BrowserContext
* context
,
68 const std::string
& uma_client_name
,
69 const base::FilePath
& db_path
,
72 uma_client_name_(uma_client_name
),
73 task_queue_(new DelayedTaskQueue()),
74 extension_registry_observer_(this) {
75 extension_registry_observer_
.Add(ExtensionRegistry::Get(context
));
78 // Don't Init() until the first page is loaded or the embedder explicitly
82 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME
,
83 content::NotificationService::AllBrowserContextsAndSources());
89 StateStore::StateStore(content::BrowserContext
* context
,
90 scoped_ptr
<ValueStore
> value_store
)
91 : store_(value_store
.Pass()),
92 task_queue_(new DelayedTaskQueue()),
93 extension_registry_observer_(this) {
94 extension_registry_observer_
.Add(ExtensionRegistry::Get(context
));
96 // This constructor is for testing. No need to delay Init.
100 StateStore::~StateStore() {
103 void StateStore::RequestInitAfterDelay() {
107 void StateStore::RegisterKey(const std::string
& key
) {
108 registered_keys_
.insert(key
);
111 void StateStore::GetExtensionValue(const std::string
& extension_id
,
112 const std::string
& key
,
113 ReadCallback callback
) {
114 task_queue_
->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Get
,
115 base::Unretained(&store_
),
116 GetFullKey(extension_id
, key
),
120 void StateStore::SetExtensionValue(const std::string
& extension_id
,
121 const std::string
& key
,
122 scoped_ptr
<base::Value
> value
) {
123 task_queue_
->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Set
,
124 base::Unretained(&store_
),
125 GetFullKey(extension_id
, key
),
126 base::Passed(&value
)));
129 void StateStore::RemoveExtensionValue(const std::string
& extension_id
,
130 const std::string
& key
) {
131 task_queue_
->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Remove
,
132 base::Unretained(&store_
),
133 GetFullKey(extension_id
, key
)));
136 bool StateStore::IsInitialized() const {
137 return task_queue_
->ready();
140 void StateStore::Observe(int type
,
141 const content::NotificationSource
& source
,
142 const content::NotificationDetails
& details
) {
143 DCHECK_EQ(type
, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME
);
144 registrar_
.RemoveAll();
148 void StateStore::OnExtensionWillBeInstalled(
149 content::BrowserContext
* browser_context
,
150 const Extension
* extension
,
153 const std::string
& old_name
) {
154 RemoveKeysForExtension(extension
->id());
157 void StateStore::OnExtensionUninstalled(
158 content::BrowserContext
* browser_context
,
159 const Extension
* extension
,
160 extensions::UninstallReason reason
) {
161 RemoveKeysForExtension(extension
->id());
164 void StateStore::Init() {
165 // Could be called twice if InitAfterDelay() is requested explicitly by the
166 // embedder in addition to internally after first page load.
170 if (!db_path_
.empty())
171 store_
.Init(uma_client_name_
, db_path_
);
172 task_queue_
->SetReady();
175 void StateStore::InitAfterDelay() {
179 base::MessageLoop::current()->PostDelayedTask(
181 base::Bind(&StateStore::Init
, AsWeakPtr()),
182 base::TimeDelta::FromSeconds(kInitDelaySeconds
));
185 void StateStore::RemoveKeysForExtension(const std::string
& extension_id
) {
186 for (std::set
<std::string
>::iterator key
= registered_keys_
.begin();
187 key
!= registered_keys_
.end();
189 task_queue_
->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Remove
,
190 base::Unretained(&store_
),
191 GetFullKey(extension_id
, *key
)));
195 } // namespace extensions