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.
5 #include "chrome/browser/extensions/state_store.h"
8 #include "base/message_loop/message_loop.h"
9 #include "chrome/browser/chrome_notification_types.h"
10 #include "content/public/browser/notification_service.h"
11 #include "content/public/browser/notification_types.h"
12 #include "extensions/common/extension.h"
16 // Delay, in seconds, before we should open the State Store database. We
17 // defer it to avoid slowing down startup. See http://crbug.com/161848
18 const int kInitDelaySeconds
= 1;
20 std::string
GetFullKey(const std::string
& extension_id
,
21 const std::string
& key
) {
22 return extension_id
+ "." + key
;
27 namespace extensions
{
29 // Helper class to delay tasks until we're ready to start executing them.
30 class StateStore::DelayedTaskQueue
{
32 DelayedTaskQueue() : ready_(false) {}
33 ~DelayedTaskQueue() {}
35 // Queues up a task for invoking once we're ready. Invokes immediately if
36 // we're already ready.
37 void InvokeWhenReady(base::Closure task
);
39 // Marks us ready, and invokes all pending tasks.
42 // Return whether or not the DelayedTaskQueue is |ready_|.
43 bool ready() const { return ready_
; }
47 std::vector
<base::Closure
> pending_tasks_
;
50 void StateStore::DelayedTaskQueue::InvokeWhenReady(base::Closure task
) {
54 pending_tasks_
.push_back(task
);
58 void StateStore::DelayedTaskQueue::SetReady() {
61 for (size_t i
= 0; i
< pending_tasks_
.size(); ++i
)
62 pending_tasks_
[i
].Run();
63 pending_tasks_
.clear();
66 StateStore::StateStore(Profile
* profile
,
67 const base::FilePath
& db_path
,
69 : db_path_(db_path
), task_queue_(new DelayedTaskQueue()) {
70 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED
,
71 content::Source
<Profile
>(profile
));
72 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED
,
73 content::Source
<Profile
>(profile
));
76 // Don't Init until the first page is loaded or the session restored.
77 registrar_
.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME
,
78 content::NotificationService::
79 AllBrowserContextsAndSources());
80 registrar_
.Add(this, chrome::NOTIFICATION_SESSION_RESTORE_DONE
,
81 content::NotificationService::
82 AllBrowserContextsAndSources());
88 StateStore::StateStore(Profile
* profile
, scoped_ptr
<ValueStore
> value_store
)
89 : store_(value_store
.Pass()), task_queue_(new DelayedTaskQueue()) {
90 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED
,
91 content::Source
<Profile
>(profile
));
92 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED
,
93 content::Source
<Profile
>(profile
));
95 // This constructor is for testing. No need to delay Init.
99 StateStore::~StateStore() {
102 void StateStore::RegisterKey(const std::string
& key
) {
103 registered_keys_
.insert(key
);
106 void StateStore::GetExtensionValue(const std::string
& extension_id
,
107 const std::string
& key
,
108 ReadCallback callback
) {
109 task_queue_
->InvokeWhenReady(
110 base::Bind(&ValueStoreFrontend::Get
, base::Unretained(&store_
),
111 GetFullKey(extension_id
, key
), callback
));
114 void StateStore::SetExtensionValue(
115 const std::string
& extension_id
,
116 const std::string
& key
,
117 scoped_ptr
<base::Value
> value
) {
118 task_queue_
->InvokeWhenReady(
119 base::Bind(&ValueStoreFrontend::Set
, base::Unretained(&store_
),
120 GetFullKey(extension_id
, key
), base::Passed(&value
)));
123 void StateStore::RemoveExtensionValue(const std::string
& extension_id
,
124 const std::string
& key
) {
125 task_queue_
->InvokeWhenReady(
126 base::Bind(&ValueStoreFrontend::Remove
, base::Unretained(&store_
),
127 GetFullKey(extension_id
, key
)));
130 bool StateStore::IsInitialized() const { return task_queue_
->ready(); }
132 void StateStore::Observe(int type
,
133 const content::NotificationSource
& source
,
134 const content::NotificationDetails
& details
) {
136 case chrome::NOTIFICATION_EXTENSION_INSTALLED
:
137 RemoveKeysForExtension(
138 content::Details
<const InstalledExtensionInfo
>(details
)->extension
->
141 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED
:
142 RemoveKeysForExtension(
143 content::Details
<const Extension
>(details
)->id());
145 case chrome::NOTIFICATION_SESSION_RESTORE_DONE
:
146 case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME
:
147 registrar_
.Remove(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME
,
148 content::NotificationService::AllSources());
149 registrar_
.Remove(this, chrome::NOTIFICATION_SESSION_RESTORE_DONE
,
150 content::NotificationService::AllSources());
151 base::MessageLoop::current()->PostDelayedTask(FROM_HERE
,
152 base::Bind(&StateStore::Init
, AsWeakPtr()),
153 base::TimeDelta::FromSeconds(kInitDelaySeconds
));
161 void StateStore::Init() {
162 if (!db_path_
.empty())
163 store_
.Init(db_path_
);
164 task_queue_
->SetReady();
167 void StateStore::RemoveKeysForExtension(const std::string
& extension_id
) {
168 for (std::set
<std::string
>::iterator key
= registered_keys_
.begin();
169 key
!= registered_keys_
.end(); ++key
) {
170 task_queue_
->InvokeWhenReady(
171 base::Bind(&ValueStoreFrontend::Remove
, base::Unretained(&store_
),
172 GetFullKey(extension_id
, *key
)));
176 } // namespace extensions