Durable Storage: Refactor browser test and test the basic "deny" flow.
[chromium-blink-merge.git] / extensions / browser / state_store.cc
blob4a04d3a9bd3a531aa01bfda4b8b646a9ddccf9e5
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"
7 #include "base/bind.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"
15 namespace {
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;
26 } // namespace
28 namespace extensions {
30 // Helper class to delay tasks until we're ready to start executing them.
31 class StateStore::DelayedTaskQueue {
32 public:
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.
41 void SetReady();
43 // Return whether or not the DelayedTaskQueue is |ready_|.
44 bool ready() const { return ready_; }
46 private:
47 bool ready_;
48 std::vector<base::Closure> pending_tasks_;
51 void StateStore::DelayedTaskQueue::InvokeWhenReady(base::Closure task) {
52 if (ready_) {
53 task.Run();
54 } else {
55 pending_tasks_.push_back(task);
59 void StateStore::DelayedTaskQueue::SetReady() {
60 ready_ = true;
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,
70 bool deferred_load)
71 : db_path_(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));
77 if (deferred_load) {
78 // Don't Init() until the first page is loaded or the embedder explicitly
79 // requests it.
80 registrar_.Add(
81 this,
82 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
83 content::NotificationService::AllBrowserContextsAndSources());
84 } else {
85 Init();
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.
97 Init();
100 StateStore::~StateStore() {
103 void StateStore::RequestInitAfterDelay() {
104 InitAfterDelay();
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),
117 callback));
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();
145 InitAfterDelay();
148 void StateStore::OnExtensionWillBeInstalled(
149 content::BrowserContext* browser_context,
150 const Extension* extension,
151 bool is_update,
152 bool from_ephemeral,
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.
167 if (IsInitialized())
168 return;
170 if (!db_path_.empty())
171 store_.Init(uma_client_name_, db_path_);
172 task_queue_->SetReady();
175 void StateStore::InitAfterDelay() {
176 if (IsInitialized())
177 return;
179 base::MessageLoop::current()->PostDelayedTask(
180 FROM_HERE,
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();
188 ++key) {
189 task_queue_->InvokeWhenReady(base::Bind(&ValueStoreFrontend::Remove,
190 base::Unretained(&store_),
191 GetFullKey(extension_id, *key)));
195 } // namespace extensions